@capillarytech/creatives-library 8.0.287-alpha.0 → 8.0.287-alpha.2
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 +1 -1
- package/v2Components/FormBuilder/index.js +4 -2
- package/v2Containers/CreativesContainer/index.js +4 -3
- package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/content.test.js.snap +3 -24
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +4 -18
- package/v2Containers/Sms/Create/index.js +31 -3
- package/v2Containers/Sms/Create/messages.js +4 -0
- package/v2Containers/Sms/Edit/index.js +29 -3
- package/v2Containers/Sms/commonMethods.js +7 -2
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +248 -624
package/package.json
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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);
|
|
@@ -140,8 +141,16 @@ export class Create extends React.Component { // eslint-disable-line react/prefe
|
|
|
140
141
|
}
|
|
141
142
|
|
|
142
143
|
componentWillReceiveProps(nextProps) {
|
|
143
|
-
if (nextProps.
|
|
144
|
-
|
|
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);
|
|
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);
|
|
@@ -134,8 +135,14 @@ export class Edit extends React.Component { // eslint-disable-line react/prefer-
|
|
|
134
135
|
}
|
|
135
136
|
|
|
136
137
|
componentWillReceiveProps(nextProps) {
|
|
137
|
-
if (nextProps.
|
|
138
|
-
|
|
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);
|
|
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
|
|
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 =
|
|
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
|
}
|