@capillarytech/creatives-library 8.0.290-alpha.3 → 8.0.290

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 (76) hide show
  1. package/constants/unified.js +1 -0
  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 +222 -84
  7. package/utils/tests/commonUtil.test.js +124 -147
  8. package/utils/tests/tagValidations.test.js +358 -280
  9. package/v2Components/CommonTestAndPreview/DeliverySettings/DeliverySettings.scss +33 -0
  10. package/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.js +397 -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 +243 -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 +33 -1
  18. package/v2Components/CommonTestAndPreview/actions.js +20 -0
  19. package/v2Components/CommonTestAndPreview/constants.js +10 -0
  20. package/v2Components/CommonTestAndPreview/index.js +133 -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 +782 -0
  25. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/index.test.js +200 -0
  26. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/utils/parseSenderDetailsResponse.test.js +235 -0
  27. package/v2Components/CommonTestAndPreview/tests/SendTestMessage.test.js +127 -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 +214 -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 +162 -84
  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/SlideBoxFooter.js +1 -3
  46. package/v2Containers/CreativesContainer/index.js +6 -19
  47. package/v2Containers/Email/index.js +5 -1
  48. package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +62 -10
  49. package/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +115 -12
  50. package/v2Containers/FTP/index.js +51 -2
  51. package/v2Containers/FTP/messages.js +4 -0
  52. package/v2Containers/InApp/index.js +96 -1
  53. package/v2Containers/InApp/tests/index.test.js +6 -17
  54. package/v2Containers/InappAdvance/index.js +103 -2
  55. package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/content.test.js.snap +24 -3
  56. package/v2Containers/Line/Container/Text/index.js +1 -0
  57. package/v2Containers/MobilePush/Create/index.js +16 -6
  58. package/v2Containers/MobilePush/Edit/index.js +16 -6
  59. package/v2Containers/MobilePushNew/index.js +33 -2
  60. package/v2Containers/Rcs/index.js +37 -12
  61. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +667 -16
  62. package/v2Containers/Sms/Create/index.js +3 -35
  63. package/v2Containers/Sms/Create/messages.js +0 -4
  64. package/v2Containers/Sms/Edit/index.js +3 -33
  65. package/v2Containers/Sms/commonMethods.js +6 -6
  66. package/v2Containers/SmsTrai/Edit/index.js +47 -6
  67. package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +147 -6
  68. package/v2Containers/Viber/index.js +1 -0
  69. package/v2Containers/WebPush/Create/hooks/useTagManagement.js +3 -1
  70. package/v2Containers/WebPush/Create/hooks/useTagManagement.test.js +7 -0
  71. package/v2Containers/WebPush/Create/index.js +2 -2
  72. package/v2Containers/WebPush/Create/utils/validation.js +2 -17
  73. package/v2Containers/WebPush/Create/utils/validation.test.js +24 -0
  74. package/v2Containers/Whatsapp/index.js +18 -10
  75. package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +25849 -3524
  76. package/v2Containers/Zalo/index.js +11 -3
@@ -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,16 +140,8 @@ export class Create extends React.Component { // eslint-disable-line react/prefe
141
140
  }
142
141
 
143
142
  componentWillReceiveProps(nextProps) {
144
- if (!nextProps.isFullMode && nextProps.isGetFormData) {
145
- // Trigger validation first; response will be sent in setFormValidity callback so pasted content is validated
146
- this.setState({ startValidation: true, pendingGetFormData: true });
147
- // Fallback: if FormBuilder never calls onFormValidityChange (e.g. early return), still respond to parent
148
- this.pendingGetFormDataTimeout = setTimeout(() => {
149
- if (this.state.pendingGetFormData && this.props.getFormSubscriptionData) {
150
- this.props.getFormSubscriptionData(this.getFormData());
151
- this.setState({ pendingGetFormData: false, startValidation: false });
152
- }
153
- }, 300);
143
+ if (nextProps.location.query.module === 'library' && nextProps.isGetFormData) {
144
+ nextProps.getFormSubscriptionData(this.getFormData());
154
145
  } else if (nextProps.isGetFormData && this.props.isFullMode && !this.props.Create.createTemplateInProgress) {
155
146
  this.startValidation();
156
147
  }
@@ -180,9 +171,6 @@ export class Create extends React.Component { // eslint-disable-line react/prefe
180
171
  }
181
172
 
182
173
  componentWillUnmount() {
183
- if (this.pendingGetFormDataTimeout) {
184
- clearTimeout(this.pendingGetFormDataTimeout);
185
- }
186
174
  if (this.props.setIsLoadingContent) {
187
175
  this.props.setIsLoadingContent(true); // setting isLoading of CreativesContainer so that slidebox foot can be hidden till content is loaded
188
176
  }
@@ -361,20 +349,7 @@ export class Create extends React.Component { // eslint-disable-line react/prefe
361
349
  }
362
350
 
363
351
  setFormValidity(isFormValid, errorData) {
364
- this.setState({ isFormValid, errorData }, () => {
365
- if (this.state.pendingGetFormData && this.props.getFormSubscriptionData) {
366
- if (this.pendingGetFormDataTimeout) {
367
- clearTimeout(this.pendingGetFormDataTimeout);
368
- this.pendingGetFormDataTimeout = null;
369
- }
370
- this.props.getFormSubscriptionData(this.getFormData());
371
- this.setState({ pendingGetFormData: false, startValidation: false });
372
- } else if (this.state.pendingGetFormData && !isFormValid) {
373
- // When the user clicked "Done" and validation failed, discard the save intent so that
374
- // fixing the error later doesn't auto-submit. The user must click "Done" again.
375
- this.setState({ pendingGetFormData: false, startValidation: false });
376
- }
377
- });
352
+ this.setState({isFormValid, errorData});
378
353
  }
379
354
 
380
355
  injectMessages(elem) {
@@ -995,13 +970,6 @@ export class Create extends React.Component { // eslint-disable-line react/prefe
995
970
  }
996
971
 
997
972
  saveFormData() {
998
- // In library mode the template is submitted via getFormSubscriptionData (triggered by startValidation →
999
- // onFormValidityChange → setFormValidity). Calling createTemplate API here would set
1000
- // createTemplateInProgress: true in redux and, because the slidebox closes before the API responds,
1001
- // that flag would never be reset – causing the spinner to be stuck on the next open.
1002
- if (!this.props.isFullMode) {
1003
- return;
1004
- }
1005
973
  //Logic to save in db etc
1006
974
  const formData = _.cloneDeep(this.state.formData);
1007
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,14 +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) {
139
- this.setState({ startValidation: true, pendingGetFormData: true });
140
- this.pendingGetFormDataTimeout = setTimeout(() => {
141
- if (this.state.pendingGetFormData && this.props.getFormSubscriptionData) {
142
- this.props.getFormSubscriptionData(this.getFormData());
143
- this.setState({ pendingGetFormData: false, startValidation: false });
144
- }
145
- }, 300);
137
+ if (nextProps.location.query.module === 'library' && nextProps.isGetFormData) {
138
+ nextProps.getFormSubscriptionData(this.getFormData());
146
139
  }
147
140
  if ( nextProps.location.query.module === 'library' && nextProps.subscriptionTemplateDetails && nextProps.subscriptionTemplateDetails.name && _.isEmpty(this.state.editData) && !_.isEmpty(this.state.schema)) {
148
141
  this.setEditState(nextProps.subscriptionTemplateDetails);
@@ -196,9 +189,6 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
196
189
  }
197
190
 
198
191
  componentWillUnmount() {
199
- if (this.pendingGetFormDataTimeout) {
200
- clearTimeout(this.pendingGetFormDataTimeout);
201
- }
202
192
  if (this.props.setIsLoadingContent) {
203
193
  this.props.setIsLoadingContent(true); // setting isLoading of CreativesContainer so that slidebox foot can be hidden till content is loaded
204
194
  }
@@ -327,20 +317,7 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
327
317
  }
328
318
 
329
319
  setFormValidity(isFormValid, errorData) {
330
- this.setState({ isFormValid, errorData }, () => {
331
- if (this.state.pendingGetFormData && this.props.getFormSubscriptionData) {
332
- if (this.pendingGetFormDataTimeout) {
333
- clearTimeout(this.pendingGetFormDataTimeout);
334
- this.pendingGetFormDataTimeout = null;
335
- }
336
- this.props.getFormSubscriptionData(this.getFormData());
337
- this.setState({ pendingGetFormData: false, startValidation: false });
338
- } else if (this.state.pendingGetFormData && !isFormValid) {
339
- // When the user clicked "Done" and validation failed, discard the save intent so that
340
- // fixing the error later doesn't auto-submit. The user must click "Done" again.
341
- this.setState({ pendingGetFormData: false, startValidation: false });
342
- }
343
- });
320
+ this.setState({isFormValid, errorData});
344
321
  }
345
322
 
346
323
  getFormData(e, value) {
@@ -946,13 +923,6 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
946
923
  this.setState({startValidation: false});
947
924
  }
948
925
  saveFormData() {
949
- // In library mode the template is submitted via getFormSubscriptionData, not editTemplate API.
950
- // Calling editTemplate here would set editTemplateInProgress: true in redux and, because the
951
- // slidebox closes before the API responds, that flag would never be reset – causing the spinner
952
- // to be stuck on the next open.
953
- if (!this.props.isFullMode) {
954
- return;
955
- }
956
926
  //Logic to save in db etc
957
927
  //saveFormData gets called only when validation result is true
958
928
 
@@ -1,18 +1,18 @@
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);
11
- const isBraceError = Boolean(err0['bracket-error']);
9
+ const isSmsInvalid = Object.values(errorData[0]).includes(true);
12
10
  if (isSmsInvalid) {
11
+ const invalidTags = errorData[0]['invalid-tags'];
12
+ if (!isEmpty(invalidTags)) {
13
+ errorMessage.description = `${intl.formatMessage(messages.invalidTags)}: ${invalidTags.join(',')} `;
14
+ }
13
15
  CapNotification.error(errorMessage);
14
- } else if (isBraceError) {
15
- // Do not trigger toast for this path; footer error is the reliable UX in SMS library flow.
16
16
  }
17
17
  }
18
18
  }
@@ -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,8 +288,6 @@ export const SmsTraiEdit = (props) => {
261
288
  };
262
289
 
263
290
  const onSubmitWrapper = () => {
264
- setIsLiquidValidationError(false);
265
- setLiquidErrorMessages({});
266
291
  const content = updatedSmsEditor.join('');
267
292
  const onError = ({ standardErrors, liquidErrors }) => {
268
293
  setLiquidErrorMessages({
@@ -273,8 +298,6 @@ export const SmsTraiEdit = (props) => {
273
298
  };
274
299
 
275
300
  const onSuccess = () => {
276
- setIsLiquidValidationError(false);
277
- setLiquidErrorMessages({});
278
301
  onDoneCallback();
279
302
  };
280
303
  validateLiquidTemplateContent(content, {
@@ -283,6 +306,10 @@ export const SmsTraiEdit = (props) => {
283
306
  messages: formBuilderMessages,
284
307
  onError,
285
308
  onSuccess,
309
+ tagLookupMap: metaEntities?.tagLookupMap,
310
+ eventContextTags,
311
+ isLiquidFlow: true,
312
+ forwardedTags: {},
286
313
  });
287
314
  };
288
315
 
@@ -521,6 +548,17 @@ export const SmsTraiEdit = (props) => {
521
548
  return countVarChar;
522
549
  };
523
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
+
524
562
  const disablehandler = () => {
525
563
  if (traiData && !isEmpty(traiData)) {
526
564
  const msg = get(traiData, `versions.base.sms-editor`, '');
@@ -566,6 +604,7 @@ export const SmsTraiEdit = (props) => {
566
604
  setShowTestAndPreviewSlidebox(false);
567
605
  };
568
606
 
607
+ const isLiquidSupportFeatureEnabled = hasLiquidSupportFeature();
569
608
  return (
570
609
  <>
571
610
  <CapSpin spinning={loading || fetchingLiquidTags} tip={fetchingLiquidTags && formatMessage(formBuilderMessages.liquidSpinText)}>
@@ -623,6 +662,7 @@ export const SmsTraiEdit = (props) => {
623
662
  <CapRow>
624
663
  {smsLengthForVar()}
625
664
  </CapRow>
665
+ {isTagValidationError && tagValidationErrorMessage()}
626
666
  <CapCheckbox onChange={unicodeHandler} checked={isUnicodeAllowed} disabled={disablehandler()}>
627
667
  {formatMessage(messages.unicodeLabel)}
628
668
  </CapCheckbox>
@@ -653,8 +693,9 @@ export const SmsTraiEdit = (props) => {
653
693
  <FormattedMessage {...messages.testAndPreviewButtonLabel} />
654
694
  </CapButton>
655
695
  <CapButton
656
- onClick={onSubmitWrapper}
696
+ onClick={isLiquidSupportFeatureEnabled ? onSubmitWrapper : onDoneCallback}
657
697
  className="create-msg"
698
+ disabled={isTagValidationError || (isLiquidSupportFeatureEnabled && !isObject(metaEntities?.tagLookupMap))}
658
699
  >
659
700
  <FormattedMessage {...messages.saveButtonLabel} />
660
701
  </CapButton>