@capillarytech/creatives-library 8.0.292-alpha.0 → 8.0.293

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 (80) hide show
  1. package/constants/unified.js +1 -3
  2. package/initialState.js +2 -0
  3. package/package.json +1 -1
  4. package/utils/common.js +8 -5
  5. package/utils/commonUtils.js +85 -4
  6. package/utils/tagValidations.js +223 -83
  7. package/utils/tests/commonUtil.test.js +124 -147
  8. package/utils/tests/tagValidations.test.js +358 -441
  9. package/v2Components/CommonTestAndPreview/DeliverySettings/DeliverySettings.scss +33 -0
  10. package/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.js +422 -0
  11. package/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.scss +35 -0
  12. package/v2Components/CommonTestAndPreview/DeliverySettings/TECH_DETAILING_DELIVERY_SETTINGS.md +725 -0
  13. package/v2Components/CommonTestAndPreview/DeliverySettings/constants.js +92 -0
  14. package/v2Components/CommonTestAndPreview/DeliverySettings/index.js +251 -0
  15. package/v2Components/CommonTestAndPreview/DeliverySettings/messages.js +111 -0
  16. package/v2Components/CommonTestAndPreview/DeliverySettings/utils/parseSenderDetailsResponse.js +91 -0
  17. package/v2Components/CommonTestAndPreview/SendTestMessage.js +51 -1
  18. package/v2Components/CommonTestAndPreview/actions.js +20 -0
  19. package/v2Components/CommonTestAndPreview/constants.js +10 -0
  20. package/v2Components/CommonTestAndPreview/index.js +148 -15
  21. package/v2Components/CommonTestAndPreview/reducer.js +47 -0
  22. package/v2Components/CommonTestAndPreview/sagas.js +60 -0
  23. package/v2Components/CommonTestAndPreview/selectors.js +51 -0
  24. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/ModifyDeliverySettings.test.js +889 -0
  25. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/index.test.js +222 -0
  26. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/utils/parseSenderDetailsResponse.test.js +235 -0
  27. package/v2Components/CommonTestAndPreview/tests/SendTestMessage.test.js +135 -0
  28. package/v2Components/CommonTestAndPreview/tests/actions.test.js +50 -0
  29. package/v2Components/CommonTestAndPreview/tests/constants.test.js +18 -0
  30. package/v2Components/CommonTestAndPreview/tests/index.test.js +342 -1
  31. package/v2Components/CommonTestAndPreview/tests/reducer.test.js +118 -0
  32. package/v2Components/CommonTestAndPreview/tests/sagas.test.js +145 -0
  33. package/v2Components/CommonTestAndPreview/tests/selectors.test.js +146 -0
  34. package/v2Components/ErrorInfoNote/index.js +5 -2
  35. package/v2Components/FormBuilder/index.js +203 -137
  36. package/v2Components/FormBuilder/messages.js +8 -0
  37. package/v2Components/HtmlEditor/HTMLEditor.js +5 -0
  38. package/v2Components/HtmlEditor/__tests__/HTMLEditor.apiErrors.test.js +1 -0
  39. package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +15 -0
  40. package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +2 -1
  41. package/v2Components/TestAndPreviewSlidebox/index.js +14 -0
  42. package/v2Containers/Cap/mockData.js +14 -0
  43. package/v2Containers/Cap/reducer.js +55 -3
  44. package/v2Containers/Cap/tests/reducer.test.js +102 -0
  45. package/v2Containers/CreativesContainer/SlideBoxContent.js +1 -5
  46. package/v2Containers/CreativesContainer/SlideBoxFooter.js +5 -13
  47. package/v2Containers/CreativesContainer/index.js +7 -30
  48. package/v2Containers/Email/index.js +5 -1
  49. package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +70 -23
  50. package/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +137 -29
  51. package/v2Containers/FTP/index.js +51 -2
  52. package/v2Containers/FTP/messages.js +4 -0
  53. package/v2Containers/InApp/index.js +104 -4
  54. package/v2Containers/InApp/tests/index.test.js +6 -17
  55. package/v2Containers/InappAdvance/index.js +108 -4
  56. package/v2Containers/InappAdvance/tests/index.test.js +0 -2
  57. package/v2Containers/Line/Container/Text/index.js +1 -0
  58. package/v2Containers/MobilePush/Create/index.js +19 -42
  59. package/v2Containers/MobilePush/Edit/index.js +19 -42
  60. package/v2Containers/MobilePushNew/index.js +32 -12
  61. package/v2Containers/MobilepushWrapper/index.js +1 -3
  62. package/v2Containers/Rcs/index.js +37 -12
  63. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +697 -12
  64. package/v2Containers/Sms/Create/index.js +3 -39
  65. package/v2Containers/Sms/Create/messages.js +0 -4
  66. package/v2Containers/Sms/Edit/index.js +3 -35
  67. package/v2Containers/Sms/commonMethods.js +6 -3
  68. package/v2Containers/SmsTrai/Edit/index.js +52 -12
  69. package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +207 -6
  70. package/v2Containers/SmsWrapper/index.js +0 -2
  71. package/v2Containers/Viber/index.js +1 -0
  72. package/v2Containers/WebPush/Create/hooks/useTagManagement.js +3 -1
  73. package/v2Containers/WebPush/Create/hooks/useTagManagement.test.js +7 -0
  74. package/v2Containers/WebPush/Create/index.js +2 -2
  75. package/v2Containers/WebPush/Create/utils/validation.js +2 -17
  76. package/v2Containers/WebPush/Create/utils/validation.test.js +24 -59
  77. package/v2Containers/Whatsapp/index.js +18 -10
  78. package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +26242 -4225
  79. package/v2Containers/Zalo/index.js +11 -3
  80. package/v2Containers/Sms/tests/commonMethods.test.js +0 -122
@@ -51,7 +51,6 @@ export class Create extends React.Component { // eslint-disable-line react/prefe
51
51
  modalContent: {title: "Alert", body: "Do you really want to delete this version?", type: 'confirm', id: 'sms-version-modal'},
52
52
  showTestAndPreviewSlidebox: false,
53
53
  isTestAndPreviewMode: false,
54
- pendingGetFormData: false,
55
54
  };
56
55
  this.saveFormData = this.saveFormData.bind(this);
57
56
  this.onFormDataChange = this.onFormDataChange.bind(this);
@@ -141,9 +140,8 @@ export class Create extends React.Component { // eslint-disable-line react/prefe
141
140
  }
142
141
 
143
142
  componentWillReceiveProps(nextProps) {
144
- // Only trigger on actual Done click (isGetFormData false -> true). Prevents auto-submit after user fixes brace error.
145
- if (!nextProps.isFullMode && nextProps.isGetFormData && !this.props.isGetFormData) {
146
- this.setState({ startValidation: true, pendingGetFormData: true });
143
+ if (nextProps.location.query.module === 'library' && nextProps.isGetFormData) {
144
+ nextProps.getFormSubscriptionData(this.getFormData());
147
145
  } else if (nextProps.isGetFormData && this.props.isFullMode && !this.props.Create.createTemplateInProgress) {
148
146
  this.startValidation();
149
147
  }
@@ -173,9 +171,6 @@ export class Create extends React.Component { // eslint-disable-line react/prefe
173
171
  }
174
172
 
175
173
  componentWillUnmount() {
176
- if (this.pendingGetFormDataTimeout) {
177
- clearTimeout(this.pendingGetFormDataTimeout);
178
- }
179
174
  if (this.props.setIsLoadingContent) {
180
175
  this.props.setIsLoadingContent(true); // setting isLoading of CreativesContainer so that slidebox foot can be hidden till content is loaded
181
176
  }
@@ -204,10 +199,6 @@ export class Create extends React.Component { // eslint-disable-line react/prefe
204
199
  if (currentTab) {
205
200
  this.setState({currentTab});
206
201
  }
207
- // Clear footer validation errors on input change so they refresh on next validation
208
- if (this.props.showLiquidErrorInFooter) {
209
- this.props.showLiquidErrorInFooter({ STANDARD_ERROR_MSG: [], LIQUID_ERROR_MSG: [] });
210
- }
211
202
  }
212
203
 
213
204
  onTagSelect(data, currentTab) {
@@ -358,25 +349,7 @@ export class Create extends React.Component { // eslint-disable-line react/prefe
358
349
  }
359
350
 
360
351
  setFormValidity(isFormValid, errorData) {
361
- this.setState({ isFormValid, errorData }, () => {
362
- if (this.state.pendingGetFormData && !isFormValid) {
363
- this.setState({ pendingGetFormData: false, startValidation: false });
364
- // Reset parent's Done state so next Done click is a fresh attempt
365
- if (this.props.onValidationFail) {
366
- this.props.onValidationFail();
367
- }
368
- return;
369
- }
370
- // In library mode with SMS, submit only when FormBuilder calls onSubmit (after liquid validation).
371
- if (this.state.pendingGetFormData && this.props.getFormSubscriptionData && this.props.isFullMode) {
372
- if (this.pendingGetFormDataTimeout) {
373
- clearTimeout(this.pendingGetFormDataTimeout);
374
- this.pendingGetFormDataTimeout = null;
375
- }
376
- this.props.getFormSubscriptionData(this.getFormData());
377
- this.setState({ pendingGetFormData: false, startValidation: false });
378
- }
379
- });
352
+ this.setState({isFormValid, errorData});
380
353
  }
381
354
 
382
355
  injectMessages(elem) {
@@ -997,15 +970,6 @@ export class Create extends React.Component { // eslint-disable-line react/prefe
997
970
  }
998
971
 
999
972
  saveFormData() {
1000
- // In library mode: FormBuilder calls onSubmit only after liquid validation succeeds.
1001
- // Submit to parent here so the slidebox can close with valid data.
1002
- if (!this.props.isFullMode) {
1003
- if (this.state.pendingGetFormData && this.props.getFormSubscriptionData) {
1004
- this.props.getFormSubscriptionData(this.getFormData());
1005
- this.setState({ pendingGetFormData: false, startValidation: false });
1006
- }
1007
- return;
1008
- }
1009
973
  //Logic to save in db etc
1010
974
  const formData = _.cloneDeep(this.state.formData);
1011
975
  const obj = {};
@@ -90,10 +90,6 @@ export default defineMessages({
90
90
  id: 'creatives.containersV2.Create.validationError',
91
91
  defaultMessage: 'Validation error',
92
92
  },
93
- "unbalancedCurlyBraces": {
94
- id: 'creatives.containersV2.Create.unbalancedCurlyBraces',
95
- defaultMessage: 'Please close all curly braces in the message.',
96
- },
97
93
  "smsTemplateCreatedSuccess": {
98
94
  id: 'creatives.containersV2.Create.smsTemplateCreatedSuccess',
99
95
  defaultMessage: 'SMS Template Created Successfully',
@@ -52,7 +52,6 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
52
52
  modalContent: {title: "Alert", body: "Do you really want to delete this version?", type: 'confirm', id: 'sms-version-modal'},
53
53
  showTestAndPreviewSlidebox: false,
54
54
  isTestAndPreviewMode: false,
55
- pendingGetFormData: false,
56
55
  };
57
56
  this.saveFormData = this.saveFormData.bind(this);
58
57
  this.onFormDataChange = this.onFormDataChange.bind(this);
@@ -135,8 +134,8 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
135
134
  }
136
135
 
137
136
  componentWillReceiveProps(nextProps) {
138
- if (!nextProps.isFullMode && nextProps.isGetFormData && !this.props.isGetFormData) {
139
- this.setState({ startValidation: true, pendingGetFormData: true });
137
+ if (nextProps.location.query.module === 'library' && nextProps.isGetFormData) {
138
+ nextProps.getFormSubscriptionData(this.getFormData());
140
139
  }
141
140
  if ( nextProps.location.query.module === 'library' && nextProps.subscriptionTemplateDetails && nextProps.subscriptionTemplateDetails.name && _.isEmpty(this.state.editData) && !_.isEmpty(this.state.schema)) {
142
141
  this.setEditState(nextProps.subscriptionTemplateDetails);
@@ -190,9 +189,6 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
190
189
  }
191
190
 
192
191
  componentWillUnmount() {
193
- if (this.pendingGetFormDataTimeout) {
194
- clearTimeout(this.pendingGetFormDataTimeout);
195
- }
196
192
  if (this.props.setIsLoadingContent) {
197
193
  this.props.setIsLoadingContent(true); // setting isLoading of CreativesContainer so that slidebox foot can be hidden till content is loaded
198
194
  }
@@ -218,10 +214,6 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
218
214
  if (currentTab) {
219
215
  this.setState({currentTab});
220
216
  }
221
- // Clear footer validation errors on input change so they refresh on next validation
222
- if (this.props.showLiquidErrorInFooter) {
223
- this.props.showLiquidErrorInFooter({ STANDARD_ERROR_MSG: [], LIQUID_ERROR_MSG: [] });
224
- }
225
217
  }
226
218
 
227
219
  onVersionNameChange() {
@@ -325,23 +317,7 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
325
317
  }
326
318
 
327
319
  setFormValidity(isFormValid, errorData) {
328
- this.setState({ isFormValid, errorData }, () => {
329
- if (this.state.pendingGetFormData && !isFormValid) {
330
- this.setState({ pendingGetFormData: false, startValidation: false });
331
- if (this.props.onValidationFail) {
332
- this.props.onValidationFail();
333
- }
334
- return;
335
- }
336
- if (this.state.pendingGetFormData && this.props.getFormSubscriptionData && this.props.isFullMode) {
337
- if (this.pendingGetFormDataTimeout) {
338
- clearTimeout(this.pendingGetFormDataTimeout);
339
- this.pendingGetFormDataTimeout = null;
340
- }
341
- this.props.getFormSubscriptionData(this.getFormData());
342
- this.setState({ pendingGetFormData: false, startValidation: false });
343
- }
344
- });
320
+ this.setState({isFormValid, errorData});
345
321
  }
346
322
 
347
323
  getFormData(e, value) {
@@ -947,14 +923,6 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
947
923
  this.setState({startValidation: false});
948
924
  }
949
925
  saveFormData() {
950
- // In library mode: FormBuilder calls onSubmit only after liquid validation succeeds.
951
- if (!this.props.isFullMode) {
952
- if (this.state.pendingGetFormData && this.props.getFormSubscriptionData) {
953
- this.props.getFormSubscriptionData(this.getFormData());
954
- this.setState({ pendingGetFormData: false, startValidation: false });
955
- }
956
- return;
957
- }
958
926
  //Logic to save in db etc
959
927
  //saveFormData gets called only when validation result is true
960
928
 
@@ -1,14 +1,17 @@
1
1
  import isEmpty from 'lodash/isEmpty';
2
- import CapNotification from '@capillarytech/cap-ui-library/CapNotification';
2
+ import { CapNotification } from '@capillarytech/cap-ui-library';
3
3
  import messages from './Create/messages';
4
4
  export function showError() {
5
5
  const {intl} = this.props;
6
6
  const {errorData} = this.state;
7
7
  const errorMessage = {key: 'validation-error', message: intl.formatMessage(messages.validationError)};
8
8
  if (!isEmpty(this.state.formData) && !this.state.isFormValid) {
9
- const err0 = errorData[0] || {};
10
- const isSmsInvalid = Object.values(err0).includes(true);
9
+ const isSmsInvalid = Object.values(errorData[0]).includes(true);
11
10
  if (isSmsInvalid) {
11
+ const invalidTags = errorData[0]['invalid-tags'];
12
+ if (!isEmpty(invalidTags)) {
13
+ errorMessage.description = `${intl.formatMessage(messages.invalidTags)}: ${invalidTags.join(',')} `;
14
+ }
12
15
  CapNotification.error(errorMessage);
13
16
  }
14
17
  }
@@ -39,8 +39,10 @@ import formBuilderMessages from '../../../v2Components/FormBuilder/messages';
39
39
  import UnifiedPreview from '../../../v2Components/CommonTestAndPreview/UnifiedPreview';
40
40
  import TestAndPreviewSlidebox from '../../../v2Components/TestAndPreviewSlidebox';
41
41
  import withCreatives from '../../../hoc/withCreatives';
42
+ import { validateTags } from '../../../utils/tagValidations';
42
43
  import {
43
44
  CHARLIMIT,
45
+ SMS,
44
46
  SMS_TRAI_VAR,
45
47
  TAG,
46
48
  EMBEDDED,
@@ -49,15 +51,16 @@ import {
49
51
  ALL,
50
52
  LIBRARY,
51
53
  } from './constants';
52
- import { SMS } from '../../CreativesContainer/constants';
53
54
  import v2EditSmsReducer from '../../Sms/Edit/reducer';
54
55
  import { v2SmsEditSagas } from '../../Sms/Edit/sagas';
55
56
  import ErrorInfoNote from '../../../v2Components/ErrorInfoNote';
56
57
  import { validateLiquidTemplateContent } from '../../../utils/commonUtils';
58
+ import { hasLiquidSupportFeature } from '../../../utils/common';
57
59
  import { ANDROID } from '../../../v2Components/CommonTestAndPreview/constants';
58
60
 
59
61
  let varMap = {};
60
62
  let traiData = {};
63
+ let tagValidationResponse = {};
61
64
  const { TextArea } = CapInput;
62
65
  const { CapLabelInline } = CapLabel;
63
66
 
@@ -91,6 +94,7 @@ export const SmsTraiEdit = (props) => {
91
94
  const [tags, updateTags] = useState([]);
92
95
  const [textAreaId, updateTextAreaId] = useState();
93
96
  const [isValidationError, updateIsValidationError] = useState(false);
97
+ const [isTagValidationError, updateIsTagValidationError] = useState(false);
94
98
  const [totalMessageLength, setTotalMessageLength] = useState(0);
95
99
  const [isUnicodeAllowed, updateIsUnicodeAllowed] = useState(true);
96
100
  const [showMsgLengthNote, updateshowMsgLengthNote] = useState(false);
@@ -225,6 +229,29 @@ export const SmsTraiEdit = (props) => {
225
229
  }
226
230
  }, []);
227
231
 
232
+ //performs tag validation
233
+ useEffect(() => {
234
+ if (
235
+ !isFullMode &&
236
+ updatedSmsEditor?.length > 0 &&
237
+ !updatedSmsEditor.includes(SMS_TRAI_VAR)
238
+ ) {
239
+ tagValidationResponse =
240
+ validateTags({
241
+ content: updatedSmsEditor.join(''),
242
+ tagsParam: tags,
243
+ injectedTagsParams: injectedTags,
244
+ location,
245
+ tagModule: getDefaultTags,
246
+ eventContextTags,
247
+ isFullMode,
248
+ }) || {};
249
+ updateIsTagValidationError(
250
+ tagValidationResponse.unsupportedTags.length > 0,
251
+ );
252
+ }
253
+ }, [updatedSmsEditor, tags]);
254
+
228
255
  const computeUpdatedSmsEditor = () => {
229
256
  const arr = [...tempMsgArray];
230
257
  const varMapKeys = Object.keys(varMap)?.map((key) => Number(key.slice(8)))?.sort((a, b) => a - b) || [];
@@ -261,13 +288,6 @@ export const SmsTraiEdit = (props) => {
261
288
  };
262
289
 
263
290
  const onSubmitWrapper = () => {
264
- setIsLiquidValidationError(false);
265
- setLiquidErrorMessages({});
266
- // Liquid validation (extractTags) only in library mode
267
- if (isFullMode) {
268
- onDoneCallback();
269
- return;
270
- }
271
291
  const content = updatedSmsEditor.join('');
272
292
  const onError = ({ standardErrors, liquidErrors }) => {
273
293
  setLiquidErrorMessages({
@@ -278,8 +298,6 @@ export const SmsTraiEdit = (props) => {
278
298
  };
279
299
 
280
300
  const onSuccess = () => {
281
- setIsLiquidValidationError(false);
282
- setLiquidErrorMessages({});
283
301
  onDoneCallback();
284
302
  };
285
303
  validateLiquidTemplateContent(content, {
@@ -288,6 +306,10 @@ export const SmsTraiEdit = (props) => {
288
306
  messages: formBuilderMessages,
289
307
  onError,
290
308
  onSuccess,
309
+ tagLookupMap: metaEntities?.tagLookupMap,
310
+ eventContextTags,
311
+ isLiquidFlow: true,
312
+ forwardedTags: {},
291
313
  });
292
314
  };
293
315
 
@@ -526,6 +548,17 @@ export const SmsTraiEdit = (props) => {
526
548
  return countVarChar;
527
549
  };
528
550
 
551
+ const tagValidationErrorMessage = () => {
552
+ const { unsupportedTags = [] } = tagValidationResponse;
553
+ let tagError = '';
554
+ if (unsupportedTags.length > 0) {
555
+ tagError = formatMessage(messages.unsupportedTagsValidationError, {
556
+ unsupportedTags,
557
+ });
558
+ }
559
+ return <CapError>{tagError}</CapError>;
560
+ };
561
+
529
562
  const disablehandler = () => {
530
563
  if (traiData && !isEmpty(traiData)) {
531
564
  const msg = get(traiData, `versions.base.sms-editor`, '');
@@ -558,7 +591,11 @@ export const SmsTraiEdit = (props) => {
558
591
  }
559
592
  const templateRaw = smsBase['updated-sms-editor'] || smsBase['sms-editor'] || '';
560
593
  const template = Array.isArray(templateRaw) ? templateRaw.join('') : templateRaw;
561
- return { templateConfigs: { templateId: smsBase.template_id, template } };
594
+ return {
595
+ templateConfigs: {
596
+ templateId: smsBase.template_id, template, traiDltEnabled: true, registeredSenderIds: get(traiData, `versions.base.header`, []),
597
+ },
598
+ };
562
599
  };
563
600
 
564
601
  // Handle test and preview button click
@@ -571,6 +608,7 @@ export const SmsTraiEdit = (props) => {
571
608
  setShowTestAndPreviewSlidebox(false);
572
609
  };
573
610
 
611
+ const isLiquidSupportFeatureEnabled = hasLiquidSupportFeature();
574
612
  return (
575
613
  <>
576
614
  <CapSpin spinning={loading || fetchingLiquidTags} tip={fetchingLiquidTags && formatMessage(formBuilderMessages.liquidSpinText)}>
@@ -628,6 +666,7 @@ export const SmsTraiEdit = (props) => {
628
666
  <CapRow>
629
667
  {smsLengthForVar()}
630
668
  </CapRow>
669
+ {isTagValidationError && tagValidationErrorMessage()}
631
670
  <CapCheckbox onChange={unicodeHandler} checked={isUnicodeAllowed} disabled={disablehandler()}>
632
671
  {formatMessage(messages.unicodeLabel)}
633
672
  </CapCheckbox>
@@ -658,8 +697,9 @@ export const SmsTraiEdit = (props) => {
658
697
  <FormattedMessage {...messages.testAndPreviewButtonLabel} />
659
698
  </CapButton>
660
699
  <CapButton
661
- onClick={onSubmitWrapper}
700
+ onClick={isLiquidSupportFeatureEnabled ? onSubmitWrapper : onDoneCallback}
662
701
  className="create-msg"
702
+ disabled={isTagValidationError || (isLiquidSupportFeatureEnabled && !isObject(metaEntities?.tagLookupMap))}
663
703
  >
664
704
  <FormattedMessage {...messages.saveButtonLabel} />
665
705
  </CapButton>