@capillarytech/creatives-library 8.0.123 → 8.0.125-alpha.0
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/containers/App/constants.js +1 -0
- package/package.json +1 -1
- package/services/api.js +1 -1
- package/tests/integration/TemplateCreation/TemplateCreation.integration.test.js +8 -3
- package/tests/integration/TemplateCreation/api-response.js +5 -0
- package/tests/integration/TemplateCreation/msw-handler.js +42 -63
- package/utils/common.js +7 -0
- package/utils/commonUtils.js +2 -6
- package/utils/createPayload.js +240 -0
- package/utils/tests/createPayload.test.js +761 -0
- package/v2Components/CapDeviceContent/index.js +1 -0
- package/v2Components/CapImageUpload/index.js +51 -45
- package/v2Components/CapInAppCTA/index.js +1 -0
- package/v2Components/CapMpushCTA/constants.js +25 -0
- package/v2Components/CapMpushCTA/index.js +332 -0
- package/v2Components/CapMpushCTA/index.scss +95 -0
- package/v2Components/CapMpushCTA/messages.js +89 -0
- package/v2Components/CapTagList/index.js +177 -120
- package/v2Components/CapVideoUpload/constants.js +3 -0
- package/v2Components/CapVideoUpload/index.js +167 -110
- package/v2Components/CapVideoUpload/messages.js +16 -0
- package/v2Components/Carousel/index.js +15 -13
- package/v2Components/ErrorInfoNote/style.scss +1 -0
- package/v2Components/MobilePushPreviewV2/index.js +37 -5
- package/v2Components/TemplatePreview/_templatePreview.scss +114 -72
- package/v2Components/TemplatePreview/assets/images/Android _ With date and time.svg +29 -0
- package/v2Components/TemplatePreview/assets/images/android.svg +9 -0
- package/v2Components/TemplatePreview/assets/images/iOS _ With date and time.svg +26 -0
- package/v2Components/TemplatePreview/assets/images/ios.svg +9 -0
- package/v2Components/TemplatePreview/index.js +178 -50
- package/v2Components/TemplatePreview/messages.js +4 -0
- package/v2Containers/CreativesContainer/SlideBoxContent.js +7 -8
- package/v2Containers/CreativesContainer/index.js +194 -138
- package/v2Containers/InApp/constants.js +1 -1
- package/v2Containers/InApp/index.js +13 -13
- package/v2Containers/MobilePush/Create/index.js +1 -0
- package/v2Containers/MobilePushNew/actions.js +116 -0
- package/v2Containers/MobilePushNew/components/CtaButtons.js +170 -0
- package/v2Containers/MobilePushNew/components/MediaUploaders.js +686 -0
- package/v2Containers/MobilePushNew/components/PlatformContentFields.js +279 -0
- package/v2Containers/MobilePushNew/components/index.js +5 -0
- package/v2Containers/MobilePushNew/components/tests/CtaButtons.test.js +779 -0
- package/v2Containers/MobilePushNew/components/tests/MediaUploaders.test.js +2114 -0
- package/v2Containers/MobilePushNew/components/tests/PlatformContentFields.test.js +343 -0
- package/v2Containers/MobilePushNew/constants.js +115 -0
- package/v2Containers/MobilePushNew/hooks/tests/usePlatformSync.test.js +1299 -0
- package/v2Containers/MobilePushNew/hooks/tests/useUpload.test.js +1223 -0
- package/v2Containers/MobilePushNew/hooks/usePlatformSync.js +246 -0
- package/v2Containers/MobilePushNew/hooks/useUpload.js +709 -0
- package/v2Containers/MobilePushNew/index.js +1937 -0
- package/v2Containers/MobilePushNew/index.scss +308 -0
- package/v2Containers/MobilePushNew/messages.js +226 -0
- package/v2Containers/MobilePushNew/reducer.js +160 -0
- package/v2Containers/MobilePushNew/sagas.js +198 -0
- package/v2Containers/MobilePushNew/selectors.js +55 -0
- package/v2Containers/MobilePushNew/tests/reducer.test.js +741 -0
- package/v2Containers/MobilePushNew/tests/sagas.test.js +863 -0
- package/v2Containers/MobilePushNew/tests/selectors.test.js +425 -0
- package/v2Containers/MobilePushNew/tests/utils.test.js +322 -0
- package/v2Containers/MobilePushNew/utils.js +33 -0
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +5 -5
- package/v2Containers/TagList/index.js +56 -10
- package/v2Containers/Templates/_templates.scss +101 -1
- package/v2Containers/Templates/index.js +147 -35
- package/v2Containers/Templates/messages.js +8 -0
- package/v2Containers/Templates/sagas.js +2 -0
- package/v2Containers/Whatsapp/constants.js +1 -0
|
@@ -22,7 +22,9 @@ import { isEmpty, get } from 'lodash';
|
|
|
22
22
|
import './index.scss';
|
|
23
23
|
import Gallery from '../../v2Containers/Assets/Gallery';
|
|
24
24
|
import { MAX_SUPPORTED_IMAGE_SIZE } from './constants';
|
|
25
|
-
import {
|
|
25
|
+
import {
|
|
26
|
+
FACEBOOK, INAPP, RCS, WHATSAPP, VIBER,
|
|
27
|
+
} from "../../v2Containers/CreativesContainer/constants";
|
|
26
28
|
|
|
27
29
|
import messages from './messages';
|
|
28
30
|
function CapImageUpload(props) {
|
|
@@ -48,14 +50,14 @@ function CapImageUpload(props) {
|
|
|
48
50
|
} = props;
|
|
49
51
|
const {
|
|
50
52
|
formatMessage,
|
|
51
|
-
|
|
53
|
+
} = intl || {};
|
|
52
54
|
|
|
53
55
|
|
|
54
56
|
useEffect(() => {
|
|
55
57
|
const imageDataObj = imageData[`uploadedAssetData${index}`];
|
|
56
58
|
if (!isEmpty(imageDataObj)) {
|
|
57
|
-
const { secure_file_path = ''
|
|
58
|
-
updateImageSrc(secure_file_path
|
|
59
|
+
const { secure_file_path = '' } = get(imageDataObj, 'metaInfo', {});
|
|
60
|
+
updateImageSrc(secure_file_path);
|
|
59
61
|
}
|
|
60
62
|
}, [imageData[`uploadedAssetData${index}`]]);
|
|
61
63
|
|
|
@@ -65,7 +67,7 @@ function CapImageUpload(props) {
|
|
|
65
67
|
const {CapHeadingSpan} = CapHeading;
|
|
66
68
|
const ImageComponent = useCallback(
|
|
67
69
|
() => (
|
|
68
|
-
|
|
70
|
+
<>
|
|
69
71
|
{
|
|
70
72
|
!isEmpty(imageSrc) ? (
|
|
71
73
|
<div className={`image-container upload ${props.ifError ? 'error' : ''}`}>
|
|
@@ -74,10 +76,10 @@ function CapImageUpload(props) {
|
|
|
74
76
|
)}
|
|
75
77
|
</div>
|
|
76
78
|
) : null}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
79
|
+
</>
|
|
80
|
+
),
|
|
81
|
+
[imageSrc],
|
|
82
|
+
);
|
|
81
83
|
|
|
82
84
|
const WithLabel = LabelHOC(ImageComponent);
|
|
83
85
|
|
|
@@ -147,10 +149,13 @@ function CapImageUpload(props) {
|
|
|
147
149
|
const onReUpload = useCallback(() => {
|
|
148
150
|
updateImageSrc('');
|
|
149
151
|
updateOnReUpload();
|
|
152
|
+
// Don't automatically trigger file dialog - let user choose between computer and gallery
|
|
150
153
|
}, []);
|
|
151
154
|
|
|
152
155
|
const onGalleryImageSelect = useCallback((imageTemplate) => {
|
|
153
|
-
const {
|
|
156
|
+
const {
|
|
157
|
+
secure_file_path: image, width, height, file_size: size,
|
|
158
|
+
} = get(imageTemplate, 'metaInfo', {});
|
|
154
159
|
updateDrawerRequirement(false);
|
|
155
160
|
if (!allowedExtensionsRegex.test(image) || height > imgHeight || width > imgWidth || size > imgSize ) {
|
|
156
161
|
updateImageErrorMessage(formatMessage(messages.imageErrorDesc));
|
|
@@ -176,7 +181,7 @@ function CapImageUpload(props) {
|
|
|
176
181
|
isFullMode={isFullMode}
|
|
177
182
|
isLineAsset
|
|
178
183
|
onGalleryImageSelect={onGalleryImageSelect}
|
|
179
|
-
|
|
184
|
+
/>
|
|
180
185
|
</>
|
|
181
186
|
);
|
|
182
187
|
}, []);
|
|
@@ -194,34 +199,35 @@ function CapImageUpload(props) {
|
|
|
194
199
|
|
|
195
200
|
const getImageSection = useCallback(() => {
|
|
196
201
|
if (imageSrc === "") {
|
|
197
|
-
return (
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
<
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
<
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
<
|
|
211
|
-
|
|
212
|
-
{channel !== WHATSAPP && (
|
|
213
|
-
<CapButton
|
|
214
|
-
className="dragger-button gallery-select"
|
|
215
|
-
type="secondary"
|
|
216
|
-
onClick={onGalleryClick}
|
|
217
|
-
>
|
|
218
|
-
<FormattedMessage {...messages.uploadGallery} />
|
|
202
|
+
return (
|
|
203
|
+
<>
|
|
204
|
+
<CapUploader.CapDragger
|
|
205
|
+
customRequest={capUploaderCustomRequest}
|
|
206
|
+
className="form-builder-dragger grey-background"
|
|
207
|
+
showUploadList={!isImageError}
|
|
208
|
+
>
|
|
209
|
+
<CapHeading className="dragger-title" type="h7">
|
|
210
|
+
<FormattedMessage {...messages.dragAndDrop} />
|
|
211
|
+
</CapHeading>
|
|
212
|
+
<CapHeading className="dragger-or" type="label6">
|
|
213
|
+
<FormattedMessage {...messages.or} />
|
|
214
|
+
</CapHeading>
|
|
215
|
+
<CapButton className="dragger-button upload-image" type="secondary">
|
|
216
|
+
<FormattedMessage {...messages.uploadComputer} />
|
|
219
217
|
</CapButton>
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
218
|
+
{channel !== WHATSAPP && (
|
|
219
|
+
<CapButton
|
|
220
|
+
className="dragger-button gallery-select"
|
|
221
|
+
type="secondary"
|
|
222
|
+
onClick={onGalleryClick}
|
|
223
|
+
>
|
|
224
|
+
<FormattedMessage {...messages.uploadGallery} />
|
|
225
|
+
</CapButton>
|
|
226
|
+
)}
|
|
227
|
+
</CapUploader.CapDragger>
|
|
228
|
+
<CapError type="error" className="upload-image-error">
|
|
229
|
+
{isImageError}
|
|
230
|
+
</CapError>
|
|
225
231
|
</>
|
|
226
232
|
);
|
|
227
233
|
}
|
|
@@ -242,26 +248,26 @@ function CapImageUpload(props) {
|
|
|
242
248
|
return (
|
|
243
249
|
<div style={style} className="cap-custom-image-upload">
|
|
244
250
|
<WithLabel
|
|
245
|
-
key=
|
|
251
|
+
key="with-label"
|
|
246
252
|
ifError={!!isImageError}
|
|
247
253
|
|
|
248
|
-
|
|
249
|
-
<form encType="multipart/form-data" id=
|
|
254
|
+
/>
|
|
255
|
+
<form encType="multipart/form-data" id="form" className={className}>
|
|
250
256
|
<input
|
|
251
|
-
key=
|
|
257
|
+
key="imgFile"
|
|
252
258
|
style={{ display: 'none' }}
|
|
253
|
-
id="
|
|
259
|
+
id="imageFileName"
|
|
254
260
|
type="file"
|
|
255
261
|
onChange={(e) => uploadImages(e, { files: e.target.files })}
|
|
256
262
|
accept={supportedExtensions || "image/*"}
|
|
257
|
-
|
|
263
|
+
/>
|
|
258
264
|
{getImageSection()}
|
|
259
265
|
<CapDrawer
|
|
260
266
|
content={getGalleryDrawerContent()}
|
|
261
267
|
visible={isDrawerRequired}
|
|
262
268
|
width={430}
|
|
263
269
|
onClose={() => updateDrawerRequirement(false)}
|
|
264
|
-
|
|
270
|
+
/>
|
|
265
271
|
</form>
|
|
266
272
|
<div className="image-info-wrapper">
|
|
267
273
|
{channel === WHATSAPP && (
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { FormattedMessage } from 'react-intl';
|
|
3
|
+
import messages from './messages';
|
|
4
|
+
|
|
5
|
+
export const DEEP_LINK = 'DEEP_LINK';
|
|
6
|
+
export const EXTERNAL_URL = 'EXTERNAL_URL';
|
|
7
|
+
export const WEBSITE = 'WEBSITE';
|
|
8
|
+
|
|
9
|
+
export const CTA_OPTIONS = [
|
|
10
|
+
{
|
|
11
|
+
key: DEEP_LINK,
|
|
12
|
+
value: DEEP_LINK,
|
|
13
|
+
label: <FormattedMessage {...messages.ctaLinkTypeDeep} />,
|
|
14
|
+
tooltipLabel: <FormattedMessage {...messages.ctaOptionDisabledTooltipDeepLink} />,
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
key: EXTERNAL_URL,
|
|
18
|
+
value: EXTERNAL_URL,
|
|
19
|
+
label: <FormattedMessage {...messages.ctaLinkTypeExternal} />,
|
|
20
|
+
tooltipLabel: <FormattedMessage {...messages.ctaOptionDisabledTooltipExternalLink} />,
|
|
21
|
+
},
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
export const BTN_MAX_LENGTH = 20;
|
|
25
|
+
export const URL_MAX_LENGTH = 2000;
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
import React, { useState, useEffect, useRef } from "react";
|
|
2
|
+
import { injectIntl } from "react-intl";
|
|
3
|
+
import "react-phone-input-2/lib/style.css";
|
|
4
|
+
import cloneDeep from "lodash/cloneDeep";
|
|
5
|
+
import CapHeading from "@capillarytech/cap-ui-library/CapHeading";
|
|
6
|
+
import CapColumn from "@capillarytech/cap-ui-library/CapColumn";
|
|
7
|
+
import CapInput from "@capillarytech/cap-ui-library/CapInput";
|
|
8
|
+
import CapButton from "@capillarytech/cap-ui-library/CapButton";
|
|
9
|
+
import CapRow from "@capillarytech/cap-ui-library/CapRow";
|
|
10
|
+
import CapLabel from "@capillarytech/cap-ui-library/CapLabel";
|
|
11
|
+
import CapIcon from "@capillarytech/cap-ui-library/CapIcon";
|
|
12
|
+
import CapTooltip from "@capillarytech/cap-ui-library/CapTooltip";
|
|
13
|
+
import CapSelect from "@capillarytech/cap-ui-library/CapSelect";
|
|
14
|
+
import CapTag from '@capillarytech/cap-ui-library/CapTag';
|
|
15
|
+
import globalMessages from "../../v2Containers/Cap/messages";
|
|
16
|
+
import inAppMsg from "../../v2Containers/InApp/messages";
|
|
17
|
+
import messages from "./messages";
|
|
18
|
+
import './index.scss';
|
|
19
|
+
import {
|
|
20
|
+
isUrl,
|
|
21
|
+
isValidText,
|
|
22
|
+
} from "../../v2Containers/Line/Container/Wrapper/utils";
|
|
23
|
+
import {
|
|
24
|
+
BTN_MAX_LENGTH,
|
|
25
|
+
DEEP_LINK,
|
|
26
|
+
EXTERNAL_URL,
|
|
27
|
+
CTA_OPTIONS,
|
|
28
|
+
URL_MAX_LENGTH,
|
|
29
|
+
} from "./constants";
|
|
30
|
+
import { PRIMARY } from "../../v2Containers/MobilePushNew/constants";
|
|
31
|
+
|
|
32
|
+
export const CapMpushCTA = (props) => {
|
|
33
|
+
const {
|
|
34
|
+
intl,
|
|
35
|
+
ctaData = [],
|
|
36
|
+
updateHandler,
|
|
37
|
+
deleteHandler,
|
|
38
|
+
deepLink,
|
|
39
|
+
buttonType,
|
|
40
|
+
} = props;
|
|
41
|
+
const { formatMessage } = intl;
|
|
42
|
+
|
|
43
|
+
const [urlError, setUrlError] = useState(false);
|
|
44
|
+
const [buttonError, setButtonError] = useState(false);
|
|
45
|
+
const [ctaDeepLinkValue, setCtaDeepLinkValue] = useState(ctaData[0]?.url || "");
|
|
46
|
+
const [localUrlValues, setLocalUrlValues] = useState({});
|
|
47
|
+
// Track which URLs have been manually cleared to prevent restoration
|
|
48
|
+
const clearedUrlsRef = useRef(new Set());
|
|
49
|
+
const selectedDeepLink = deepLink?.find(link => link?.value === ctaData[0]?.url);
|
|
50
|
+
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
const urlValues = {};
|
|
53
|
+
ctaData.forEach((cta) => {
|
|
54
|
+
if (cta && typeof cta.index !== 'undefined') {
|
|
55
|
+
// Don't restore URLs that have been manually cleared
|
|
56
|
+
const wasManuallyCleared = clearedUrlsRef.current.has(cta.index);
|
|
57
|
+
urlValues[cta.index] = wasManuallyCleared ? '' : (cta.url || '');
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
setLocalUrlValues(urlValues);
|
|
63
|
+
}, [ctaData]);
|
|
64
|
+
|
|
65
|
+
const updateHelper = (type, value, index) => {
|
|
66
|
+
let clonedCta = cloneDeep(ctaData[index]);
|
|
67
|
+
clonedCta = {
|
|
68
|
+
...clonedCta,
|
|
69
|
+
[type]: value,
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
if (type === 'url') {
|
|
73
|
+
setLocalUrlValues(prev => ({
|
|
74
|
+
...prev,
|
|
75
|
+
[index]: value
|
|
76
|
+
}));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
updateHandler(clonedCta, index);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const renderLength = (len, max) => (
|
|
83
|
+
<CapHeading
|
|
84
|
+
type="label1"
|
|
85
|
+
className="inapp-render-btn-length"
|
|
86
|
+
>
|
|
87
|
+
{formatMessage(inAppMsg.templateMessageLength, {
|
|
88
|
+
currentLength: len,
|
|
89
|
+
maxLength: max,
|
|
90
|
+
})}
|
|
91
|
+
</CapHeading>
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
const onButtonTextChange = ({ target }) => {
|
|
96
|
+
const { value, id } = target;
|
|
97
|
+
let errorMessage = "";
|
|
98
|
+
if (!isValidText(value)) {
|
|
99
|
+
errorMessage = formatMessage(messages.ctaButtonErrorMessage);
|
|
100
|
+
}
|
|
101
|
+
setButtonError(errorMessage);
|
|
102
|
+
updateHelper("text", value, id);
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const onUrlTypeChange = (value, index) => {
|
|
106
|
+
// Mark this URL as manually cleared to prevent restoration
|
|
107
|
+
clearedUrlsRef.current.add(index);
|
|
108
|
+
|
|
109
|
+
// Clear the URL field when switching between link types
|
|
110
|
+
updateHelper('url', '', index);
|
|
111
|
+
|
|
112
|
+
// Immediately clear the local URL state for this button
|
|
113
|
+
setLocalUrlValues(prev => ({
|
|
114
|
+
...prev,
|
|
115
|
+
[index]: ''
|
|
116
|
+
}));
|
|
117
|
+
|
|
118
|
+
// Also clear the local deep link state
|
|
119
|
+
setCtaDeepLinkValue('');
|
|
120
|
+
// Clear any URL errors
|
|
121
|
+
setUrlError(false);
|
|
122
|
+
// Update the URL type
|
|
123
|
+
updateHelper('urlType', value, index);
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
const onUrlChange = ({ target }) => {
|
|
127
|
+
const { value, dataset } = target;
|
|
128
|
+
const index = parseInt(dataset.index, 10);
|
|
129
|
+
|
|
130
|
+
// If user is typing a new URL, remove from cleared set
|
|
131
|
+
if (value && value.trim() !== '') {
|
|
132
|
+
clearedUrlsRef.current.delete(index);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
let errorMessage = false;
|
|
136
|
+
if (!isUrl(value)) {
|
|
137
|
+
errorMessage = formatMessage(messages.ctaWebsiteUrlErrorMessage);
|
|
138
|
+
}
|
|
139
|
+
setUrlError(errorMessage);
|
|
140
|
+
|
|
141
|
+
// Update local state immediately for instant UI feedback
|
|
142
|
+
setLocalUrlValues(prev => ({
|
|
143
|
+
...prev,
|
|
144
|
+
[index]: value
|
|
145
|
+
}));
|
|
146
|
+
|
|
147
|
+
updateHelper('url', value, index);
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
const onDeepLinkSelect = (value, index) => {
|
|
151
|
+
setCtaDeepLinkValue(value);
|
|
152
|
+
let errorMessage = false;
|
|
153
|
+
if (!isUrl(value)) {
|
|
154
|
+
errorMessage = formatMessage(messages.ctaWebsiteUrlErrorMessage);
|
|
155
|
+
}
|
|
156
|
+
setUrlError(errorMessage);
|
|
157
|
+
updateHelper('url', value, index);
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
const ctaSaveDisabled = (index) => {
|
|
161
|
+
const { urlType, text, url } = ctaData[index] || {};
|
|
162
|
+
if (text === "" || buttonError) {
|
|
163
|
+
return true;
|
|
164
|
+
} else if (urlType === DEEP_LINK && (ctaDeepLinkValue === "" || urlError)) {
|
|
165
|
+
return true;
|
|
166
|
+
} else if (urlType === EXTERNAL_URL && (url === "" || urlError)) {
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
const isSavedCta = (index, saved) => {
|
|
172
|
+
updateHelper("isSaved", saved, index);
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
const renderedContent = () => {
|
|
176
|
+
const renderArray = [];
|
|
177
|
+
const filteredCtaData = ctaData?.filter((cta) => {
|
|
178
|
+
if (buttonType === PRIMARY) {
|
|
179
|
+
return cta.index === 0;
|
|
180
|
+
} else {
|
|
181
|
+
return cta.index === 1;
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
filteredCtaData?.forEach((cta) => {
|
|
186
|
+
const { index, text, url, urlType, isSaved } = cta || {};
|
|
187
|
+
if (isSaved) {
|
|
188
|
+
renderArray.push(
|
|
189
|
+
<CapRow
|
|
190
|
+
className="cap-inapp-saved-cta"
|
|
191
|
+
align="middle"
|
|
192
|
+
type="flex"
|
|
193
|
+
>
|
|
194
|
+
<CapRow className="inapp-cta-row">
|
|
195
|
+
<CapColumn>
|
|
196
|
+
<CapIcon size="s" type={'launch'} className="btn-icon" />
|
|
197
|
+
</CapColumn>
|
|
198
|
+
<CapColumn className="btn-text">
|
|
199
|
+
<CapLabel type="label2" className="inapp-saved-cta-button-text">
|
|
200
|
+
{text}
|
|
201
|
+
</CapLabel>
|
|
202
|
+
</CapColumn>
|
|
203
|
+
</CapRow>
|
|
204
|
+
<CapColumn >
|
|
205
|
+
{urlType === DEEP_LINK ?
|
|
206
|
+
<CapTag className="cta-type-label">{formatMessage(messages.urlDeepLink)}</CapTag>
|
|
207
|
+
: <CapTag className="cta-type-label">{formatMessage(messages.urlExternalLink)}</CapTag>}
|
|
208
|
+
</CapColumn>
|
|
209
|
+
<CapColumn>
|
|
210
|
+
{urlType === DEEP_LINK ? selectedDeepLink?.label : ''}
|
|
211
|
+
</CapColumn>
|
|
212
|
+
{(
|
|
213
|
+
<CapRow className="cta-action-grp">
|
|
214
|
+
<CapColumn
|
|
215
|
+
className="inapp-saved-cta-edit-icon"
|
|
216
|
+
onClick={() => isSavedCta(index, false)}
|
|
217
|
+
>
|
|
218
|
+
<CapIcon size="s" type="edit" className="cta-action" />
|
|
219
|
+
</CapColumn>
|
|
220
|
+
<CapColumn onClick={() => deleteHandler(index)} className="cta-del-icon">
|
|
221
|
+
<CapIcon size="s" type="delete" className="cta-action" ariaLabel="delete-cta-icon" />
|
|
222
|
+
</CapColumn>
|
|
223
|
+
</CapRow>
|
|
224
|
+
)}
|
|
225
|
+
</CapRow>
|
|
226
|
+
);
|
|
227
|
+
} else {
|
|
228
|
+
renderArray.push(
|
|
229
|
+
<CapRow
|
|
230
|
+
className="cap-inapp-cta"
|
|
231
|
+
id={`cap-inapp-cta-${index}`}
|
|
232
|
+
>
|
|
233
|
+
<CapColumn>
|
|
234
|
+
<CapHeading type="h4" className="cta-label">
|
|
235
|
+
{buttonType === PRIMARY ? formatMessage(messages.ctaButtonText) : formatMessage(messages.ctaButtonTextSecondary)}
|
|
236
|
+
</CapHeading>
|
|
237
|
+
<CapInput
|
|
238
|
+
id={index}
|
|
239
|
+
onChange={onButtonTextChange}
|
|
240
|
+
placeholder={formatMessage(messages.ctaButtonTextPlaceholder)}
|
|
241
|
+
value={text}
|
|
242
|
+
maxLength={BTN_MAX_LENGTH}
|
|
243
|
+
errorMessage={buttonError}
|
|
244
|
+
/>
|
|
245
|
+
{renderLength(text.length, BTN_MAX_LENGTH)}
|
|
246
|
+
</CapColumn>
|
|
247
|
+
<CapColumn className="inapp-cta-buttons">
|
|
248
|
+
<CapRow style={{ width: '30%', marginRight: '10px' }}>
|
|
249
|
+
<CapHeading type="h4" className="cta-label">
|
|
250
|
+
{formatMessage(messages.ctaType)}
|
|
251
|
+
</CapHeading>
|
|
252
|
+
<CapSelect.CapCustomSelect
|
|
253
|
+
id="inapp-cta-type"
|
|
254
|
+
key="mpush-cta-type"
|
|
255
|
+
options={CTA_OPTIONS || []}
|
|
256
|
+
onChange={(value) => onUrlTypeChange(value, index)}
|
|
257
|
+
value={urlType}
|
|
258
|
+
/>
|
|
259
|
+
</CapRow>
|
|
260
|
+
{urlType === DEEP_LINK && (
|
|
261
|
+
<CapRow style={{ width: '70%' }}>
|
|
262
|
+
<CapHeading type="h4">
|
|
263
|
+
{formatMessage(messages.urlDeepLink)}
|
|
264
|
+
</CapHeading>
|
|
265
|
+
<CapSelect.CapCustomSelect
|
|
266
|
+
id="inapp-deep-link-type"
|
|
267
|
+
key="mpush-deep-link-type"
|
|
268
|
+
placeholder={formatMessage(messages.ctaDeepLinkOptionsPlaceholder)}
|
|
269
|
+
options={deepLink || []}
|
|
270
|
+
onChange={(value) => onDeepLinkSelect(value, index)}
|
|
271
|
+
value={ctaDeepLinkValue}
|
|
272
|
+
/>
|
|
273
|
+
</CapRow>
|
|
274
|
+
|
|
275
|
+
)}
|
|
276
|
+
{urlType === EXTERNAL_URL && (
|
|
277
|
+
<CapRow style={{ width: '70%' }}>
|
|
278
|
+
<CapHeading type="h4">
|
|
279
|
+
{formatMessage(messages.urlExternalLink)}
|
|
280
|
+
</CapHeading>
|
|
281
|
+
<CapInput
|
|
282
|
+
id="inapp-cta-external-link"
|
|
283
|
+
className="inapp-cta-external-link"
|
|
284
|
+
onChange={onUrlChange}
|
|
285
|
+
placeholder={formatMessage(messages.ctaExternalLinkPlaceholder)}
|
|
286
|
+
value={localUrlValues[index] || ''}
|
|
287
|
+
size="large"
|
|
288
|
+
maxLength={URL_MAX_LENGTH}
|
|
289
|
+
errorMessage={urlError}
|
|
290
|
+
data-index={index}
|
|
291
|
+
/>
|
|
292
|
+
</CapRow>
|
|
293
|
+
)}
|
|
294
|
+
</CapColumn>
|
|
295
|
+
<CapRow className="inapp-cta-save-delete-btn">
|
|
296
|
+
<CapTooltip
|
|
297
|
+
title={
|
|
298
|
+
ctaSaveDisabled(index)
|
|
299
|
+
? formatMessage(messages.ctaSaveDisabled)
|
|
300
|
+
: ""
|
|
301
|
+
}
|
|
302
|
+
placement={"bottom"}
|
|
303
|
+
>
|
|
304
|
+
<div className="button-disabled-tooltip-wrapper">
|
|
305
|
+
<CapButton
|
|
306
|
+
onClick={() => isSavedCta(index, true)}
|
|
307
|
+
disabled={ctaSaveDisabled(index)}
|
|
308
|
+
className="inapp-cta-save-btn"
|
|
309
|
+
>
|
|
310
|
+
{formatMessage(globalMessages.save)}
|
|
311
|
+
</CapButton>
|
|
312
|
+
</div>
|
|
313
|
+
</CapTooltip>
|
|
314
|
+
<CapButton
|
|
315
|
+
onClick={() => deleteHandler(index)}
|
|
316
|
+
className="inapp-cta-delete-btn"
|
|
317
|
+
type="secondary"
|
|
318
|
+
>
|
|
319
|
+
{formatMessage(globalMessages.delete)}
|
|
320
|
+
</CapButton>
|
|
321
|
+
</CapRow>
|
|
322
|
+
</CapRow>
|
|
323
|
+
);
|
|
324
|
+
}
|
|
325
|
+
});
|
|
326
|
+
return renderArray;
|
|
327
|
+
};
|
|
328
|
+
|
|
329
|
+
return renderedContent();
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
export default injectIntl(CapMpushCTA);
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
@import '~@capillarytech/cap-ui-library/styles/_variables.scss';
|
|
2
|
+
|
|
3
|
+
.cap-inapp-cta {
|
|
4
|
+
margin-top: $CAP_SPACE_16;
|
|
5
|
+
margin-left: 1.6rem;
|
|
6
|
+
padding: $CAP_SPACE_16 $CAP_SPACE_24;
|
|
7
|
+
border: 1px solid $CAP_G06;
|
|
8
|
+
border-radius: $CAP_SPACE_04;
|
|
9
|
+
|
|
10
|
+
.inapp-cta-buttons {
|
|
11
|
+
margin-top: $CAP_SPACE_12;
|
|
12
|
+
display: flex;
|
|
13
|
+
flex-direction: row;
|
|
14
|
+
align-items: flex-end;
|
|
15
|
+
justify-content: space-between;
|
|
16
|
+
|
|
17
|
+
.inapp-render-btn-length {
|
|
18
|
+
margin-top: $CAP_SPACE_12;
|
|
19
|
+
width: 90%;
|
|
20
|
+
margin-left: 52%;
|
|
21
|
+
margin-bottom: $CAP_SPACE_12;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
#inapp-deep-link-type {
|
|
26
|
+
width: 100%;
|
|
27
|
+
margin-top: $CAP_SPACE_12;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.inapp-cta-external-link {
|
|
31
|
+
margin-top: $CAP_SPACE_12;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.inapp-cta-save-delete-btn {
|
|
35
|
+
margin-top: $CAP_SPACE_16;
|
|
36
|
+
|
|
37
|
+
.inapp-cta-save-btn {
|
|
38
|
+
margin-right: $CAP_SPACE_04;
|
|
39
|
+
}
|
|
40
|
+
.inapp-cta-delete-btn {
|
|
41
|
+
margin-left: $CAP_SPACE_04;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.cap-inapp-saved-cta {
|
|
48
|
+
border: solid 1px $CAP_G06;
|
|
49
|
+
margin-left: $CAP_SPACE_20;
|
|
50
|
+
display: flex;
|
|
51
|
+
justify-content: space-between;
|
|
52
|
+
padding: $CAP_SPACE_08 $CAP_SPACE_12;
|
|
53
|
+
border-radius: $CAP_SPACE_04;
|
|
54
|
+
margin-top: $CAP_SPACE_12;
|
|
55
|
+
height: $CAP_SPACE_40;
|
|
56
|
+
|
|
57
|
+
.inapp-saved-cta-button-text {
|
|
58
|
+
font-weight: 500;
|
|
59
|
+
padding-left: $CAP_SPACE_16;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.inapp-saved-cta-edit-icon {
|
|
63
|
+
margin-left: 4.286rem;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
.cta-label {
|
|
67
|
+
margin-bottom: $CAP_SPACE_08;
|
|
68
|
+
}
|
|
69
|
+
.cta-type-label {
|
|
70
|
+
border-radius: 1rem;
|
|
71
|
+
background-color: $CAP_G08;
|
|
72
|
+
width: $CAP_SPACE_80;
|
|
73
|
+
height: $CAP_SPACE_24 !important;
|
|
74
|
+
align-items: center;
|
|
75
|
+
justify-content: center;
|
|
76
|
+
}
|
|
77
|
+
.cta-action {
|
|
78
|
+
cursor: pointer;
|
|
79
|
+
}
|
|
80
|
+
.inapp-cta-row {
|
|
81
|
+
display: flex;
|
|
82
|
+
align-items: center;
|
|
83
|
+
}
|
|
84
|
+
.cta-action-grp {
|
|
85
|
+
display: flex;
|
|
86
|
+
}
|
|
87
|
+
.cta-del-icon {
|
|
88
|
+
padding-left: 1rem;
|
|
89
|
+
}
|
|
90
|
+
.btn-text {
|
|
91
|
+
margin-left: $CAP_SPACE_08;
|
|
92
|
+
}
|
|
93
|
+
.btn-icon {
|
|
94
|
+
color: $CAP_G06;
|
|
95
|
+
}
|