@capillarytech/creatives-library 8.0.287-alpha.0 → 8.0.287-alpha.1

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": "8.0.287-alpha.0",
4
+ "version": "8.0.287-alpha.1",
5
5
  "description": "Capillary creatives ui",
6
6
  "main": "./index.js",
7
7
  "module": "./index.es.js",
@@ -2800,7 +2800,10 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
2800
2800
  this.props.showLiquidErrorInFooter(this.state.liquidErrorMessage, this.props.channel === SMS? null: this.state.currentTab);
2801
2801
  });
2802
2802
  }
2803
- else{
2803
+ // Always render the textarea regardless of the liquid error state update above.
2804
+ // Previously the textarea was inside the `else` branch, so it was not rendered during the
2805
+ // one render cycle when the liquid error message was first set – causing the input to lose
2806
+ // focus whenever a brace/tag error first appeared.
2804
2807
  if (styling === 'semantic') {
2805
2808
  columns.push(
2806
2809
  <CapColumn key="input" span={val.width} offset={offset}>
@@ -2839,7 +2842,6 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
2839
2842
  </CapColumn>
2840
2843
  );
2841
2844
  }
2842
- }
2843
2845
  };
2844
2846
 
2845
2847
 
@@ -1467,11 +1467,12 @@ export class Creatives extends React.Component {
1467
1467
  }
1468
1468
 
1469
1469
  getFormData = (template) => {
1470
+ // Always reset isGetFormData so the child does not re-send form data on every re-render
1471
+ // (e.g. when user fixes validation error by typing, we must not auto-close the slidebox)
1472
+ this.setState({ isGetFormData: false });
1470
1473
  if (template.validity) {
1471
1474
  this.setState(
1472
- {
1473
- isGetFormData: false,
1474
- },
1475
+ {},
1475
1476
  () => {
1476
1477
  const templateData = this.state.templateData ? this.state.templateData : template; //select existing or create new content
1477
1478
  const channel = templateData.type;
@@ -3117,7 +3117,6 @@ new message content.",
3117
3117
  },
3118
3118
  ]
3119
3119
  }
3120
- showTruncatedTooltip={false}
3121
3120
  size="large"
3122
3121
  style={
3123
3122
  Object {
@@ -3136,7 +3135,6 @@ new message content.",
3136
3135
  />
3137
3136
  }
3138
3137
  onChange={[Function]}
3139
- onDropdownVisibleChange={[Function]}
3140
3138
  removeIcon={
3141
3139
  <CapIcon
3142
3140
  size="s"
@@ -3201,7 +3199,6 @@ new message content.",
3201
3199
  onBlur={[Function]}
3202
3200
  onChange={[Function]}
3203
3201
  onDeselect={[Function]}
3204
- onDropdownVisibleChange={[Function]}
3205
3202
  onFocus={[Function]}
3206
3203
  onInputKeyDown={[Function]}
3207
3204
  onSearch={[Function]}
@@ -3440,11 +3437,7 @@ new message content.",
3440
3437
  }
3441
3438
  }
3442
3439
  title=""
3443
- >
3444
- <div
3445
- className="cap-select-option-tooltip"
3446
- />
3447
- </div>
3440
+ />
3448
3441
  </div>
3449
3442
  <span
3450
3443
  className="ant-select-arrow"
@@ -6947,7 +6940,6 @@ new message content.",
6947
6940
  },
6948
6941
  ]
6949
6942
  }
6950
- showTruncatedTooltip={false}
6951
6943
  size="large"
6952
6944
  style={
6953
6945
  Object {
@@ -6966,7 +6958,6 @@ new message content.",
6966
6958
  />
6967
6959
  }
6968
6960
  onChange={[Function]}
6969
- onDropdownVisibleChange={[Function]}
6970
6961
  removeIcon={
6971
6962
  <CapIcon
6972
6963
  size="s"
@@ -7031,7 +7022,6 @@ new message content.",
7031
7022
  onBlur={[Function]}
7032
7023
  onChange={[Function]}
7033
7024
  onDeselect={[Function]}
7034
- onDropdownVisibleChange={[Function]}
7035
7025
  onFocus={[Function]}
7036
7026
  onInputKeyDown={[Function]}
7037
7027
  onSearch={[Function]}
@@ -7270,11 +7260,7 @@ new message content.",
7270
7260
  }
7271
7261
  }
7272
7262
  title=""
7273
- >
7274
- <div
7275
- className="cap-select-option-tooltip"
7276
- />
7277
- </div>
7263
+ />
7278
7264
  </div>
7279
7265
  <span
7280
7266
  className="ant-select-arrow"
@@ -10721,7 +10707,6 @@ new message content.",
10721
10707
  },
10722
10708
  ]
10723
10709
  }
10724
- showTruncatedTooltip={false}
10725
10710
  size="large"
10726
10711
  style={
10727
10712
  Object {
@@ -10740,7 +10725,6 @@ new message content.",
10740
10725
  />
10741
10726
  }
10742
10727
  onChange={[Function]}
10743
- onDropdownVisibleChange={[Function]}
10744
10728
  removeIcon={
10745
10729
  <CapIcon
10746
10730
  size="s"
@@ -10805,7 +10789,6 @@ new message content.",
10805
10789
  onBlur={[Function]}
10806
10790
  onChange={[Function]}
10807
10791
  onDeselect={[Function]}
10808
- onDropdownVisibleChange={[Function]}
10809
10792
  onFocus={[Function]}
10810
10793
  onInputKeyDown={[Function]}
10811
10794
  onSearch={[Function]}
@@ -11044,11 +11027,7 @@ new message content.",
11044
11027
  }
11045
11028
  }
11046
11029
  title=""
11047
- >
11048
- <div
11049
- className="cap-select-option-tooltip"
11050
- />
11051
- </div>
11030
+ />
11052
11031
  </div>
11053
11032
  <span
11054
11033
  className="ant-select-arrow"
@@ -86505,7 +86505,6 @@ new message content.",
86505
86505
  },
86506
86506
  ]
86507
86507
  }
86508
- showTruncatedTooltip={false}
86509
86508
  size="large"
86510
86509
  style={
86511
86510
  Object {
@@ -86525,7 +86524,6 @@ new message content.",
86525
86524
  />
86526
86525
  }
86527
86526
  onChange={[Function]}
86528
- onDropdownVisibleChange={[Function]}
86529
86527
  removeIcon={
86530
86528
  <_default
86531
86529
  size="s"
@@ -86591,7 +86589,6 @@ new message content.",
86591
86589
  onBlur={[Function]}
86592
86590
  onChange={[Function]}
86593
86591
  onDeselect={[Function]}
86594
- onDropdownVisibleChange={[Function]}
86595
86592
  onFocus={[Function]}
86596
86593
  onInputKeyDown={[Function]}
86597
86594
  onSearch={[Function]}
@@ -86830,13 +86827,9 @@ new message content.",
86830
86827
  "opacity": 1,
86831
86828
  }
86832
86829
  }
86833
- title=""
86830
+ title="Vertical Medium"
86834
86831
  >
86835
- <div
86836
- className="cap-select-option-tooltip"
86837
- >
86838
- Vertical Medium
86839
- </div>
86832
+ Vertical Medium
86840
86833
  </div>
86841
86834
  </div>
86842
86835
  <span
@@ -105854,7 +105847,6 @@ new message content.",
105854
105847
  },
105855
105848
  ]
105856
105849
  }
105857
- showTruncatedTooltip={false}
105858
105850
  size="large"
105859
105851
  style={
105860
105852
  Object {
@@ -105874,7 +105866,6 @@ new message content.",
105874
105866
  />
105875
105867
  }
105876
105868
  onChange={[Function]}
105877
- onDropdownVisibleChange={[Function]}
105878
105869
  removeIcon={
105879
105870
  <_default
105880
105871
  size="s"
@@ -105940,7 +105931,6 @@ new message content.",
105940
105931
  onBlur={[Function]}
105941
105932
  onChange={[Function]}
105942
105933
  onDeselect={[Function]}
105943
- onDropdownVisibleChange={[Function]}
105944
105934
  onFocus={[Function]}
105945
105935
  onInputKeyDown={[Function]}
105946
105936
  onSearch={[Function]}
@@ -106179,13 +106169,9 @@ new message content.",
106179
106169
  "opacity": 1,
106180
106170
  }
106181
106171
  }
106182
- title=""
106172
+ title="Vertical Medium"
106183
106173
  >
106184
- <div
106185
- className="cap-select-option-tooltip"
106186
- >
106187
- Vertical Medium
106188
- </div>
106174
+ Vertical Medium
106189
106175
  </div>
106190
106176
  </div>
106191
106177
  <span
@@ -51,6 +51,7 @@ 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,
54
55
  };
55
56
  this.saveFormData = this.saveFormData.bind(this);
56
57
  this.onFormDataChange = this.onFormDataChange.bind(this);
@@ -141,7 +142,15 @@ export class Create extends React.Component { // eslint-disable-line react/prefe
141
142
 
142
143
  componentWillReceiveProps(nextProps) {
143
144
  if (nextProps.location.query.module === 'library' && nextProps.isGetFormData) {
144
- nextProps.getFormSubscriptionData(this.getFormData());
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);
145
154
  } else if (nextProps.isGetFormData && this.props.isFullMode && !this.props.Create.createTemplateInProgress) {
146
155
  this.startValidation();
147
156
  }
@@ -171,6 +180,9 @@ export class Create extends React.Component { // eslint-disable-line react/prefe
171
180
  }
172
181
 
173
182
  componentWillUnmount() {
183
+ if (this.pendingGetFormDataTimeout) {
184
+ clearTimeout(this.pendingGetFormDataTimeout);
185
+ }
174
186
  if (this.props.setIsLoadingContent) {
175
187
  this.props.setIsLoadingContent(true); // setting isLoading of CreativesContainer so that slidebox foot can be hidden till content is loaded
176
188
  }
@@ -349,7 +361,16 @@ export class Create extends React.Component { // eslint-disable-line react/prefe
349
361
  }
350
362
 
351
363
  setFormValidity(isFormValid, errorData) {
352
- this.setState({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
+ }
373
+ });
353
374
  }
354
375
 
355
376
  injectMessages(elem) {
@@ -970,6 +991,13 @@ export class Create extends React.Component { // eslint-disable-line react/prefe
970
991
  }
971
992
 
972
993
  saveFormData() {
994
+ // In library mode the template is submitted via getFormSubscriptionData (triggered by startValidation →
995
+ // onFormValidityChange → setFormValidity). Calling createTemplate API here would set
996
+ // createTemplateInProgress: true in redux and, because the slidebox closes before the API responds,
997
+ // that flag would never be reset – causing the spinner to be stuck on the next open.
998
+ if (!this.props.isFullMode) {
999
+ return;
1000
+ }
973
1001
  //Logic to save in db etc
974
1002
  const formData = _.cloneDeep(this.state.formData);
975
1003
  const obj = {};
@@ -90,6 +90,10 @@ 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
+ },
93
97
  "smsTemplateCreatedSuccess": {
94
98
  id: 'creatives.containersV2.Create.smsTemplateCreatedSuccess',
95
99
  defaultMessage: 'SMS Template Created Successfully',
@@ -52,6 +52,7 @@ 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,
55
56
  };
56
57
  this.saveFormData = this.saveFormData.bind(this);
57
58
  this.onFormDataChange = this.onFormDataChange.bind(this);
@@ -135,7 +136,13 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
135
136
 
136
137
  componentWillReceiveProps(nextProps) {
137
138
  if (nextProps.location.query.module === 'library' && nextProps.isGetFormData) {
138
- nextProps.getFormSubscriptionData(this.getFormData());
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);
139
146
  }
140
147
  if ( nextProps.location.query.module === 'library' && nextProps.subscriptionTemplateDetails && nextProps.subscriptionTemplateDetails.name && _.isEmpty(this.state.editData) && !_.isEmpty(this.state.schema)) {
141
148
  this.setEditState(nextProps.subscriptionTemplateDetails);
@@ -189,6 +196,9 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
189
196
  }
190
197
 
191
198
  componentWillUnmount() {
199
+ if (this.pendingGetFormDataTimeout) {
200
+ clearTimeout(this.pendingGetFormDataTimeout);
201
+ }
192
202
  if (this.props.setIsLoadingContent) {
193
203
  this.props.setIsLoadingContent(true); // setting isLoading of CreativesContainer so that slidebox foot can be hidden till content is loaded
194
204
  }
@@ -317,7 +327,16 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
317
327
  }
318
328
 
319
329
  setFormValidity(isFormValid, errorData) {
320
- this.setState({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
+ }
339
+ });
321
340
  }
322
341
 
323
342
  getFormData(e, value) {
@@ -923,6 +942,13 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
923
942
  this.setState({startValidation: false});
924
943
  }
925
944
  saveFormData() {
945
+ // In library mode the template is submitted via getFormSubscriptionData, not editTemplate API.
946
+ // Calling editTemplate here would set editTemplateInProgress: true in redux and, because the
947
+ // slidebox closes before the API responds, that flag would never be reset – causing the spinner
948
+ // to be stuck on the next open.
949
+ if (!this.props.isFullMode) {
950
+ return;
951
+ }
926
952
  //Logic to save in db etc
927
953
  //saveFormData gets called only when validation result is true
928
954
 
@@ -6,13 +6,18 @@ export function showError() {
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 isSmsInvalid = Object.values(errorData[0]).includes(true);
9
+ const err0 = errorData[0] || {};
10
+ const isSmsInvalid = Object.values(err0).includes(true);
11
+ const isBraceError = Boolean(err0['bracket-error']);
10
12
  if (isSmsInvalid) {
11
- const invalidTags = errorData[0]['invalid-tags'];
13
+ const invalidTags = err0['invalid-tags'];
12
14
  if (!isEmpty(invalidTags)) {
13
15
  errorMessage.description = `${intl.formatMessage(messages.invalidTags)}: ${invalidTags.join(',')} `;
14
16
  }
15
17
  CapNotification.error(errorMessage);
18
+ } else if (isBraceError) {
19
+ errorMessage.description = intl.formatMessage(messages.unbalancedCurlyBraces);
20
+ CapNotification.error(errorMessage);
16
21
  }
17
22
  }
18
23
  }