@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.
Files changed (67) hide show
  1. package/containers/App/constants.js +1 -0
  2. package/package.json +1 -1
  3. package/services/api.js +1 -1
  4. package/tests/integration/TemplateCreation/TemplateCreation.integration.test.js +8 -3
  5. package/tests/integration/TemplateCreation/api-response.js +5 -0
  6. package/tests/integration/TemplateCreation/msw-handler.js +42 -63
  7. package/utils/common.js +7 -0
  8. package/utils/commonUtils.js +2 -6
  9. package/utils/createPayload.js +240 -0
  10. package/utils/tests/createPayload.test.js +761 -0
  11. package/v2Components/CapDeviceContent/index.js +1 -0
  12. package/v2Components/CapImageUpload/index.js +51 -45
  13. package/v2Components/CapInAppCTA/index.js +1 -0
  14. package/v2Components/CapMpushCTA/constants.js +25 -0
  15. package/v2Components/CapMpushCTA/index.js +332 -0
  16. package/v2Components/CapMpushCTA/index.scss +95 -0
  17. package/v2Components/CapMpushCTA/messages.js +89 -0
  18. package/v2Components/CapTagList/index.js +177 -120
  19. package/v2Components/CapVideoUpload/constants.js +3 -0
  20. package/v2Components/CapVideoUpload/index.js +167 -110
  21. package/v2Components/CapVideoUpload/messages.js +16 -0
  22. package/v2Components/Carousel/index.js +15 -13
  23. package/v2Components/ErrorInfoNote/style.scss +1 -0
  24. package/v2Components/MobilePushPreviewV2/index.js +37 -5
  25. package/v2Components/TemplatePreview/_templatePreview.scss +114 -72
  26. package/v2Components/TemplatePreview/assets/images/Android _ With date and time.svg +29 -0
  27. package/v2Components/TemplatePreview/assets/images/android.svg +9 -0
  28. package/v2Components/TemplatePreview/assets/images/iOS _ With date and time.svg +26 -0
  29. package/v2Components/TemplatePreview/assets/images/ios.svg +9 -0
  30. package/v2Components/TemplatePreview/index.js +178 -50
  31. package/v2Components/TemplatePreview/messages.js +4 -0
  32. package/v2Containers/CreativesContainer/SlideBoxContent.js +7 -8
  33. package/v2Containers/CreativesContainer/index.js +194 -138
  34. package/v2Containers/InApp/constants.js +1 -1
  35. package/v2Containers/InApp/index.js +13 -13
  36. package/v2Containers/MobilePush/Create/index.js +1 -0
  37. package/v2Containers/MobilePushNew/actions.js +116 -0
  38. package/v2Containers/MobilePushNew/components/CtaButtons.js +170 -0
  39. package/v2Containers/MobilePushNew/components/MediaUploaders.js +686 -0
  40. package/v2Containers/MobilePushNew/components/PlatformContentFields.js +279 -0
  41. package/v2Containers/MobilePushNew/components/index.js +5 -0
  42. package/v2Containers/MobilePushNew/components/tests/CtaButtons.test.js +779 -0
  43. package/v2Containers/MobilePushNew/components/tests/MediaUploaders.test.js +2114 -0
  44. package/v2Containers/MobilePushNew/components/tests/PlatformContentFields.test.js +343 -0
  45. package/v2Containers/MobilePushNew/constants.js +115 -0
  46. package/v2Containers/MobilePushNew/hooks/tests/usePlatformSync.test.js +1299 -0
  47. package/v2Containers/MobilePushNew/hooks/tests/useUpload.test.js +1223 -0
  48. package/v2Containers/MobilePushNew/hooks/usePlatformSync.js +246 -0
  49. package/v2Containers/MobilePushNew/hooks/useUpload.js +709 -0
  50. package/v2Containers/MobilePushNew/index.js +1937 -0
  51. package/v2Containers/MobilePushNew/index.scss +308 -0
  52. package/v2Containers/MobilePushNew/messages.js +226 -0
  53. package/v2Containers/MobilePushNew/reducer.js +160 -0
  54. package/v2Containers/MobilePushNew/sagas.js +198 -0
  55. package/v2Containers/MobilePushNew/selectors.js +55 -0
  56. package/v2Containers/MobilePushNew/tests/reducer.test.js +741 -0
  57. package/v2Containers/MobilePushNew/tests/sagas.test.js +863 -0
  58. package/v2Containers/MobilePushNew/tests/selectors.test.js +425 -0
  59. package/v2Containers/MobilePushNew/tests/utils.test.js +322 -0
  60. package/v2Containers/MobilePushNew/utils.js +33 -0
  61. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +5 -5
  62. package/v2Containers/TagList/index.js +56 -10
  63. package/v2Containers/Templates/_templates.scss +101 -1
  64. package/v2Containers/Templates/index.js +147 -35
  65. package/v2Containers/Templates/messages.js +8 -0
  66. package/v2Containers/Templates/sagas.js +2 -0
  67. package/v2Containers/Whatsapp/constants.js +1 -0
@@ -327,6 +327,7 @@ const CapDeviceContent = (props) => {
327
327
  options={BUTTON_RADIO_OPTIONS}
328
328
  value={buttonType}
329
329
  onChange={onChangeButtonType}
330
+ disabled={!isAndroid}
330
331
  className="inapp-btn-radio-group"
331
332
  />
332
333
  {isBtnTypeCta && (
@@ -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 { FACEBOOK, INAPP, RCS, WHATSAPP, VIBER } from "../../v2Containers/CreativesContainer/constants";
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
- } = intl || {};
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 = '', karixFileHandle = '' } = get(imageDataObj, 'metaInfo', {});
58
- updateImageSrc(secure_file_path, karixFileHandle);
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
- [imageSrc],
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 {secure_file_path: image, width, height, file_size: size} = get(imageTemplate, 'metaInfo', {});
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
- <CapUploader.CapDragger
199
- customRequest={capUploaderCustomRequest}
200
- className="form-builder-dragger grey-background"
201
- showUploadList={!isImageError}
202
- >
203
- <CapHeading className="dragger-title" type="h7">
204
- <FormattedMessage {...messages.dragAndDrop} />
205
- </CapHeading>
206
- <CapHeading className="dragger-or" type="label6">
207
- <FormattedMessage {...messages.or} />
208
- </CapHeading>
209
- <CapButton className="dragger-button upload-image" type="secondary">
210
- <FormattedMessage {...messages.uploadComputer} />
211
- </CapButton>
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
- </CapUploader.CapDragger>
222
- <CapError type="error" className="upload-image-error">
223
- {isImageError}
224
- </CapError>
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={`with-label`}
251
+ key="with-label"
246
252
  ifError={!!isImageError}
247
253
 
248
- />
249
- <form encType="multipart/form-data" id={`form`} className={className}>
254
+ />
255
+ <form encType="multipart/form-data" id="form" className={className}>
250
256
  <input
251
- key={`imgFile`}
257
+ key="imgFile"
252
258
  style={{ display: 'none' }}
253
- id="fileName"
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 && (
@@ -38,6 +38,7 @@ export const CapInAppCTA = (props) => {
38
38
  deleteHandler,
39
39
  isEditFlow,
40
40
  deepLink,
41
+ channel,
41
42
  } = props;
42
43
  const { formatMessage } = intl;
43
44
 
@@ -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
+ }