@capillarytech/creatives-library 7.12.18 → 7.12.20
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/CapActionButton/index.js +116 -0
- package/v2Components/CapActionButton/index.scss +12 -0
- package/v2Components/CapActionButton/messages.js +29 -0
- package/v2Containers/Cap/messages.js +4 -0
- package/v2Containers/Rcs/constants.js +3 -0
- package/v2Containers/Rcs/index.js +85 -8
- package/v2Containers/Rcs/messages.js +31 -3
package/package.json
CHANGED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import { injectIntl, intlShape, FormattedMessage } from 'react-intl';
|
|
4
|
+
import {
|
|
5
|
+
CapRow,
|
|
6
|
+
CapHeading,
|
|
7
|
+
CapInput,
|
|
8
|
+
CapDivider,
|
|
9
|
+
CapButton,
|
|
10
|
+
CapTooltip,
|
|
11
|
+
CapLabel,
|
|
12
|
+
} from '@capillarytech/cap-ui-library';
|
|
13
|
+
|
|
14
|
+
import { isUrl } from '../../v2Containers/Line/Container/Wrapper/utils';
|
|
15
|
+
import globalMessages from '../../v2Containers/Cap/messages';
|
|
16
|
+
import messages from './messages';
|
|
17
|
+
import './index.scss';
|
|
18
|
+
const CapActionButton = (props) => {
|
|
19
|
+
const {
|
|
20
|
+
intl,
|
|
21
|
+
buttonTextlen,
|
|
22
|
+
type,
|
|
23
|
+
updateButtonChange,
|
|
24
|
+
suggestions = [],
|
|
25
|
+
} = props;
|
|
26
|
+
const {text = "", url = "" } = suggestions[0] || {};
|
|
27
|
+
const [buttonText, setButtonText] = useState(text || '');
|
|
28
|
+
const [buttonLink, setButtonLink] = useState(url || '');
|
|
29
|
+
const [buttonURLErrorMessage, updateButtonURLErrorMessage] = useState(false);
|
|
30
|
+
|
|
31
|
+
const { formatMessage } = intl;
|
|
32
|
+
|
|
33
|
+
const onButtonTextChange = (e) => {
|
|
34
|
+
const val = e.target.value;
|
|
35
|
+
setButtonText(val);
|
|
36
|
+
updateButtonChange([{
|
|
37
|
+
type,
|
|
38
|
+
text: val,
|
|
39
|
+
url: buttonLink,
|
|
40
|
+
}]);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const onButtonLinkChange = (e) => {
|
|
44
|
+
const val = e.target.value;
|
|
45
|
+
setButtonLink(val);
|
|
46
|
+
let errorMessage = false;
|
|
47
|
+
if (!isUrl(val)) {
|
|
48
|
+
errorMessage = formatMessage(messages.inValidUrliErrorMessage);
|
|
49
|
+
} else {
|
|
50
|
+
updateButtonChange([{
|
|
51
|
+
type,
|
|
52
|
+
text: buttonText,
|
|
53
|
+
url: val,
|
|
54
|
+
}]);
|
|
55
|
+
}
|
|
56
|
+
updateButtonURLErrorMessage(errorMessage);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
return (<CapRow
|
|
60
|
+
className="cap-action-button"
|
|
61
|
+
>
|
|
62
|
+
{/* Button text */}
|
|
63
|
+
<CapHeading type="h4">
|
|
64
|
+
<FormattedMessage {...messages.templateButtonText} />
|
|
65
|
+
</CapHeading>
|
|
66
|
+
<CapInput
|
|
67
|
+
id="rcs-template-Button-Text"
|
|
68
|
+
onChange={onButtonTextChange}
|
|
69
|
+
placeholder={formatMessage(messages.templateButtonTextPlaceholder)}
|
|
70
|
+
value={buttonText}
|
|
71
|
+
size="default"
|
|
72
|
+
maxLength={buttonTextlen}
|
|
73
|
+
suffix={
|
|
74
|
+
<CapLabel type="label1">{`${buttonText?.length} / ${buttonTextlen}`}</CapLabel>
|
|
75
|
+
}
|
|
76
|
+
/>
|
|
77
|
+
|
|
78
|
+
{/* button Link */}
|
|
79
|
+
<CapHeading
|
|
80
|
+
type="h4"
|
|
81
|
+
style={{paddingTop: "20px"}}
|
|
82
|
+
><FormattedMessage {...messages.templateButtonLink} /></CapHeading>
|
|
83
|
+
<CapInput
|
|
84
|
+
id="rcs-template-Button-link"
|
|
85
|
+
onChange={onButtonLinkChange}
|
|
86
|
+
placeholder={formatMessage(messages.templateButtonLinkPlaceholder)}
|
|
87
|
+
value={buttonLink}
|
|
88
|
+
size="default"
|
|
89
|
+
errorMessage={buttonURLErrorMessage}
|
|
90
|
+
/>
|
|
91
|
+
|
|
92
|
+
{/* divider */}
|
|
93
|
+
<CapDivider style={{ marginBottom: 16, marginTop: 23 }}/>
|
|
94
|
+
|
|
95
|
+
{/* Add button */}
|
|
96
|
+
<CapTooltip
|
|
97
|
+
placement="topLeft"
|
|
98
|
+
title={formatMessage(globalMessages.comingSoonTooltip)}
|
|
99
|
+
>
|
|
100
|
+
<CapButton
|
|
101
|
+
type="flat" style={{ opacity: "0.5",
|
|
102
|
+
cursor: "not-allowed"}} isAddBtn>
|
|
103
|
+
{formatMessage(messages.addButton)}
|
|
104
|
+
</CapButton>
|
|
105
|
+
</CapTooltip>
|
|
106
|
+
</CapRow>);
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
CapActionButton.propTypes = {
|
|
110
|
+
intl: intlShape.isRequired,
|
|
111
|
+
buttonTextlen: intlShape.isRequired,
|
|
112
|
+
type: PropTypes.string,
|
|
113
|
+
updateButtonChange: PropTypes.fun,
|
|
114
|
+
suggestions: PropTypes.array,
|
|
115
|
+
};
|
|
116
|
+
export default injectIntl(CapActionButton);
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { defineMessages } from 'react-intl';
|
|
2
|
+
const prefix = `creatives.componentsV2.CapActionButton`;
|
|
3
|
+
|
|
4
|
+
export default defineMessages({
|
|
5
|
+
templateButtonText: {
|
|
6
|
+
id: `${prefix}.templateButtonText`,
|
|
7
|
+
defaultMessage: 'Button text',
|
|
8
|
+
},
|
|
9
|
+
templateButtonTextPlaceholder: {
|
|
10
|
+
id: `${prefix}.templateButtonTextPlaceholder`,
|
|
11
|
+
defaultMessage: 'Enter button text',
|
|
12
|
+
},
|
|
13
|
+
templateButtonLink: {
|
|
14
|
+
id: `${prefix}.templateButtonLink`,
|
|
15
|
+
defaultMessage: 'Button link',
|
|
16
|
+
},
|
|
17
|
+
templateButtonLinkPlaceholder: {
|
|
18
|
+
id: `${prefix}.templateButtonLinkPlaceholder`,
|
|
19
|
+
defaultMessage: 'Enter button link',
|
|
20
|
+
},
|
|
21
|
+
addButton: {
|
|
22
|
+
id: `${prefix}.addButton`,
|
|
23
|
+
defaultMessage: 'Add button',
|
|
24
|
+
},
|
|
25
|
+
inValidUrliErrorMessage: {
|
|
26
|
+
id: `${prefix}.inValidUrliErrorMessage`,
|
|
27
|
+
defaultMessage: 'Button URL is not valid',
|
|
28
|
+
},
|
|
29
|
+
});
|
|
@@ -185,5 +185,9 @@ export default defineMessages({
|
|
|
185
185
|
defaultMessage:
|
|
186
186
|
'Unsupported tags: {unsupportedTags}. Please remove them from this message.',
|
|
187
187
|
},
|
|
188
|
+
"comingSoonTooltip": {
|
|
189
|
+
id: `creatives.containersV2.comingSoonTooltip`,
|
|
190
|
+
defaultMessage: 'Not enabled yet. Coming soon!',
|
|
191
|
+
},
|
|
188
192
|
});
|
|
189
193
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
|
|
1
2
|
export const RCS = 'RCS';
|
|
2
3
|
export const SMS = 'SMS';
|
|
3
4
|
export const MEDIUM = 'MEDIUM';
|
|
@@ -17,6 +18,8 @@ export const RCS_DLT_MODE = {
|
|
|
17
18
|
export const TEMPLATE_DESC_MAX_LENGTH = 1000;
|
|
18
19
|
export const FALLBACK_MESSAGE_MAX_LENGTH = 160;
|
|
19
20
|
export const TEMPLATE_TITLE_MAX_LENGTH = 200;
|
|
21
|
+
export const TEMPLATE_BUTTON_TEXT_MAX_LENGTH = 20;
|
|
22
|
+
|
|
20
23
|
export const TAG = 'TAG';
|
|
21
24
|
export const EMBEDDED = 'embedded';
|
|
22
25
|
export const DEFAULT = 'default';
|
|
@@ -26,6 +26,9 @@ import CapMenu from '@capillarytech/cap-ui-library/CapMenu';
|
|
|
26
26
|
import CapNotification from '@capillarytech/cap-ui-library/CapNotification';
|
|
27
27
|
import CapTooltipWithInfo from '@capillarytech/cap-ui-library/CapTooltipWithInfo';
|
|
28
28
|
import CapError from '@capillarytech/cap-ui-library/CapError';
|
|
29
|
+
import CapCheckbox from '@capillarytech/cap-ui-library/CapCheckbox';
|
|
30
|
+
import CapActionButton from '../../v2Components/CapActionButton';
|
|
31
|
+
|
|
29
32
|
import {
|
|
30
33
|
CAP_G01,
|
|
31
34
|
CAP_SPACE_16,
|
|
@@ -49,6 +52,7 @@ import {
|
|
|
49
52
|
SMS,
|
|
50
53
|
RCS_MEDIA_TYPES,
|
|
51
54
|
TEMPLATE_TITLE_MAX_LENGTH,
|
|
55
|
+
TEMPLATE_BUTTON_TEXT_MAX_LENGTH,
|
|
52
56
|
TEMPLATE_DESC_MAX_LENGTH,
|
|
53
57
|
FALLBACK_MESSAGE_MAX_LENGTH,
|
|
54
58
|
TAG,
|
|
@@ -64,7 +68,6 @@ import {
|
|
|
64
68
|
RCS_DLT_MODE,
|
|
65
69
|
MEDIUM,
|
|
66
70
|
VERTICAL,
|
|
67
|
-
RIGHT,
|
|
68
71
|
STANDALONE,
|
|
69
72
|
RICHCARD,
|
|
70
73
|
} from './constants';
|
|
@@ -78,6 +81,7 @@ import Templates from '../Templates';
|
|
|
78
81
|
import SmsTraiEdit from '../SmsTrai/Edit';
|
|
79
82
|
import TagList from '../TagList';
|
|
80
83
|
import { validateTags } from '../../utils/tagValidations';
|
|
84
|
+
const { Group: CapCheckboxGroup } = CapCheckbox;
|
|
81
85
|
export const Rcs = (props) => {
|
|
82
86
|
const {
|
|
83
87
|
intl,
|
|
@@ -126,7 +130,8 @@ export const Rcs = (props) => {
|
|
|
126
130
|
const [showDltCard, setShowDltCard] = useState(false);
|
|
127
131
|
const [fallbackPreviewmode, setFallbackPreviewmode] = useState(false);
|
|
128
132
|
const [dltPreviewData, setDltPreviewData] = useState('');
|
|
129
|
-
|
|
133
|
+
const [suggestions, setSuggestions] = useState([]);
|
|
134
|
+
const [buttonType, setButtonType] = useState('');
|
|
130
135
|
const mediaRadioOptions = [
|
|
131
136
|
{
|
|
132
137
|
value: RCS_MEDIA_TYPES.NONE,
|
|
@@ -161,12 +166,49 @@ export const Rcs = (props) => {
|
|
|
161
166
|
}
|
|
162
167
|
}
|
|
163
168
|
`;
|
|
164
|
-
|
|
169
|
+
const updateButtonChange = (val) => {
|
|
170
|
+
setSuggestions(val);
|
|
171
|
+
};
|
|
165
172
|
const RcsLabel = styled.div`
|
|
166
173
|
display: flex;
|
|
167
174
|
margin-top: 20px;
|
|
168
|
-
margin-bottom: 6px;
|
|
169
175
|
`;
|
|
176
|
+
const rcsButtonTypeOptions = [
|
|
177
|
+
{
|
|
178
|
+
label: <>
|
|
179
|
+
<div style={{display: "inline-grid"}}>
|
|
180
|
+
<CapHeading type="h4"><FormattedMessage {...messages.templateCTAButton} /></CapHeading>
|
|
181
|
+
<CapLabel type="label3" style={{ marginBottom: "17px"}}>
|
|
182
|
+
<FormattedMessage {...messages.templateCTAButtonDesc} />
|
|
183
|
+
</CapLabel>
|
|
184
|
+
</div>
|
|
185
|
+
{buttonType && <CapActionButton
|
|
186
|
+
type="CTA"
|
|
187
|
+
buttonTextlen={TEMPLATE_BUTTON_TEXT_MAX_LENGTH}
|
|
188
|
+
updateButtonChange={updateButtonChange}
|
|
189
|
+
suggestions={suggestions}
|
|
190
|
+
/>}
|
|
191
|
+
</>,
|
|
192
|
+
value: "CTA",
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
label: <CapTooltip
|
|
196
|
+
placement="topLeft"
|
|
197
|
+
title={<FormattedMessage {...globalMessages.comingSoonTooltip} />}
|
|
198
|
+
>
|
|
199
|
+
<div style={{display: "inline-grid", opacity: "0.5"}}>
|
|
200
|
+
<CapHeading type="h4" disabled>
|
|
201
|
+
<FormattedMessage {...messages.templateQRButton} />
|
|
202
|
+
</CapHeading>
|
|
203
|
+
<CapLabel type="label3" style={{ marginBottom: "17px"}} disabled>
|
|
204
|
+
<FormattedMessage {...messages.templateQRButtonDesc} />
|
|
205
|
+
</CapLabel>
|
|
206
|
+
</div>
|
|
207
|
+
</CapTooltip>,
|
|
208
|
+
value: "QR",
|
|
209
|
+
disabled: "true",
|
|
210
|
+
},
|
|
211
|
+
];
|
|
170
212
|
|
|
171
213
|
//gets template details
|
|
172
214
|
const paramObj = params || {};
|
|
@@ -194,6 +236,7 @@ export const Rcs = (props) => {
|
|
|
194
236
|
mediaType = RCS_MEDIA_TYPES.NONE,
|
|
195
237
|
title = '',
|
|
196
238
|
description = '',
|
|
239
|
+
suggestions: rcsSuggestions = [],
|
|
197
240
|
} = cardContent[0] || {};
|
|
198
241
|
const { message, templateConfigs = {} } = smsFallBackContent;
|
|
199
242
|
setTemplateName(name);
|
|
@@ -203,6 +246,11 @@ export const Rcs = (props) => {
|
|
|
203
246
|
setTemplateDesc(description);
|
|
204
247
|
setFallbackMessage(message);
|
|
205
248
|
setEditFlow(true);
|
|
249
|
+
if (rcsSuggestions.length > 0) {
|
|
250
|
+
setSuggestions(rcsSuggestions);
|
|
251
|
+
setButtonType(["CTA"]);
|
|
252
|
+
}
|
|
253
|
+
|
|
206
254
|
// for DLT Fallback message
|
|
207
255
|
if (isDltEnabled) {
|
|
208
256
|
const {
|
|
@@ -303,7 +351,7 @@ export const Rcs = (props) => {
|
|
|
303
351
|
};
|
|
304
352
|
// tag Code end
|
|
305
353
|
|
|
306
|
-
const renderLabel = (value, showLabel) => (
|
|
354
|
+
const renderLabel = (value, showLabel, desc) => (<>
|
|
307
355
|
<RcsLabel>
|
|
308
356
|
<CapHeading type="h4">{formatMessage(messages[value])}</CapHeading>
|
|
309
357
|
{showLabel && (
|
|
@@ -312,6 +360,12 @@ export const Rcs = (props) => {
|
|
|
312
360
|
</CapHeading>
|
|
313
361
|
)}
|
|
314
362
|
</RcsLabel>
|
|
363
|
+
{desc && (
|
|
364
|
+
<CapLabel type="label3" style={{ marginBottom: "17px"}}>
|
|
365
|
+
{formatMessage(messages[desc])}
|
|
366
|
+
</CapLabel>
|
|
367
|
+
)}
|
|
368
|
+
</>
|
|
315
369
|
);
|
|
316
370
|
|
|
317
371
|
const onTemplateNameChange = ({ target: { value } }) => {
|
|
@@ -399,7 +453,10 @@ export const Rcs = (props) => {
|
|
|
399
453
|
}
|
|
400
454
|
return errorMessage;
|
|
401
455
|
};
|
|
402
|
-
|
|
456
|
+
const onChangeButtonTypes = (val) => {
|
|
457
|
+
setButtonType(val[0]);
|
|
458
|
+
setSuggestions([]);
|
|
459
|
+
};
|
|
403
460
|
const renderTextComponent = (
|
|
404
461
|
<>
|
|
405
462
|
{/* template title */}
|
|
@@ -452,6 +509,14 @@ export const Rcs = (props) => {
|
|
|
452
509
|
value={templateDesc || ''}
|
|
453
510
|
maxLength={1000}
|
|
454
511
|
/>
|
|
512
|
+
{renderLabel("templateButton", true, "templateButtonDesc")}
|
|
513
|
+
<CapCheckboxGroup
|
|
514
|
+
style={{display: "grid"}}
|
|
515
|
+
options={rcsButtonTypeOptions}
|
|
516
|
+
value={buttonType}
|
|
517
|
+
onChange={onChangeButtonTypes}
|
|
518
|
+
/>
|
|
519
|
+
|
|
455
520
|
</>
|
|
456
521
|
);
|
|
457
522
|
|
|
@@ -815,6 +880,7 @@ export const Rcs = (props) => {
|
|
|
815
880
|
title: templateTitle,
|
|
816
881
|
description: templateDesc,
|
|
817
882
|
mediaType: templateMediaType,
|
|
883
|
+
...(suggestions.length > 0 && {suggestions}),
|
|
818
884
|
...(!isMediaTypeNone && {
|
|
819
885
|
media: {
|
|
820
886
|
mediaUrl: rcsImageSrc,
|
|
@@ -930,6 +996,12 @@ export const Rcs = (props) => {
|
|
|
930
996
|
if (!isMediaTypeNone && rcsImageSrc === '') {
|
|
931
997
|
return true;
|
|
932
998
|
}
|
|
999
|
+
|
|
1000
|
+
// if call to action (Button text & link) is not added
|
|
1001
|
+
const {text, url} = suggestions[0] || {};
|
|
1002
|
+
if (buttonType && !(text && url) ) {
|
|
1003
|
+
return true;
|
|
1004
|
+
}
|
|
933
1005
|
if (templateDescError || fallbackMessageError) {
|
|
934
1006
|
return true;
|
|
935
1007
|
}
|
|
@@ -951,7 +1023,12 @@ export const Rcs = (props) => {
|
|
|
951
1023
|
);
|
|
952
1024
|
}
|
|
953
1025
|
const tempMsg = dltPreviewData === '' ? fallbackMessage : dltPreviewData;
|
|
954
|
-
|
|
1026
|
+
let mediaTypeMsg = isMediaTypeNone ? 'textMessage' : 'image';
|
|
1027
|
+
mediaTypeMsg = formatMessage(messages[mediaTypeMsg]);
|
|
1028
|
+
const {text, url} = suggestions[0] || {};
|
|
1029
|
+
if (buttonType && !(text && url) ) {
|
|
1030
|
+
mediaTypeMsg = `${formatMessage(messages.buttonTextAndUrl)} ${mediaTypeMsg} `;
|
|
1031
|
+
}
|
|
955
1032
|
return (
|
|
956
1033
|
<>
|
|
957
1034
|
<CapRow className="cap-rcs-creatives">
|
|
@@ -993,7 +1070,7 @@ export const Rcs = (props) => {
|
|
|
993
1070
|
title={
|
|
994
1071
|
isDisableDone()
|
|
995
1072
|
? formatMessage(messages.rcsDoneBtnToolTip, {
|
|
996
|
-
type:
|
|
1073
|
+
type: mediaTypeMsg,
|
|
997
1074
|
})
|
|
998
1075
|
: ''
|
|
999
1076
|
}
|
|
@@ -16,7 +16,7 @@ export default defineMessages({
|
|
|
16
16
|
},
|
|
17
17
|
image: {
|
|
18
18
|
id: `${prefix}.image`,
|
|
19
|
-
defaultMessage: 'image',
|
|
19
|
+
defaultMessage: 'and image',
|
|
20
20
|
},
|
|
21
21
|
mediaVideo: {
|
|
22
22
|
id: `${prefix}.mediaVideo`,
|
|
@@ -52,7 +52,7 @@ export default defineMessages({
|
|
|
52
52
|
},
|
|
53
53
|
textMessage: {
|
|
54
54
|
id: `${prefix}.textMessage`,
|
|
55
|
-
defaultMessage: 'text message',
|
|
55
|
+
defaultMessage: 'and text message',
|
|
56
56
|
},
|
|
57
57
|
templateDescLengthError: {
|
|
58
58
|
id: `${prefix}.templateDescLengthError`,
|
|
@@ -60,7 +60,7 @@ export default defineMessages({
|
|
|
60
60
|
},
|
|
61
61
|
rcsDoneBtnToolTip: {
|
|
62
62
|
id: `${prefix}.rcsDoneBtnToolTip`,
|
|
63
|
-
defaultMessage: 'Please add template name
|
|
63
|
+
defaultMessage: 'Please add template name {type} to proceed further',
|
|
64
64
|
},
|
|
65
65
|
fallbackLabel: {
|
|
66
66
|
id: `${prefix}.fallbackLabel`,
|
|
@@ -119,4 +119,32 @@ export default defineMessages({
|
|
|
119
119
|
id: `${prefix}.fallbackPreviewtitle`,
|
|
120
120
|
defaultMessage: 'Preview of fallback SMS',
|
|
121
121
|
},
|
|
122
|
+
templateButton: {
|
|
123
|
+
id: `${prefix}.templateTitle`,
|
|
124
|
+
defaultMessage: 'Buttons',
|
|
125
|
+
},
|
|
126
|
+
templateButtonDesc: {
|
|
127
|
+
id: `${prefix}.templateButtonDesc`,
|
|
128
|
+
defaultMessage: 'These will be show clickable buttons below your message.',
|
|
129
|
+
},
|
|
130
|
+
templateCTAButton: {
|
|
131
|
+
id: `${prefix}.templateCTAButton`,
|
|
132
|
+
defaultMessage: 'Call to action',
|
|
133
|
+
},
|
|
134
|
+
templateCTAButtonDesc: {
|
|
135
|
+
id: `${prefix}.templateCTAButtonDesc`,
|
|
136
|
+
defaultMessage: 'Create up to 3 buttons that let customers respond to your messages or take action.',
|
|
137
|
+
},
|
|
138
|
+
templateQRButton: {
|
|
139
|
+
id: `${prefix}.templateQRButton`,
|
|
140
|
+
defaultMessage: 'Quick reply',
|
|
141
|
+
},
|
|
142
|
+
templateQRButtonDesc: {
|
|
143
|
+
id: `${prefix}.templateQRButtonDesc`,
|
|
144
|
+
defaultMessage: 'Create up to 3 buttons that let customers respond to your messages or take action.',
|
|
145
|
+
},
|
|
146
|
+
buttonTextAndUrl: {
|
|
147
|
+
id: `${prefix}.buttonTextAndUrl`,
|
|
148
|
+
defaultMessage: ', CTA button text & url ',
|
|
149
|
+
},
|
|
122
150
|
});
|