@capillarytech/creatives-library 7.17.91 → 7.17.92
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/index.js +6 -0
- package/package.json +1 -1
- package/routes.js +5 -0
- package/services/api.js +5 -0
- package/v2Components/CapDeviceContent/index.js +338 -0
- package/v2Components/CapDeviceContent/index.scss +115 -0
- package/v2Components/CapDeviceContent/messages.js +107 -0
- package/v2Components/CapDeviceContent/tests/index.test.js +75 -0
- package/v2Components/CapImageUpload/index.js +10 -3
- package/v2Components/CapImageUpload/messages.js +4 -0
- package/v2Components/CapInAppCTA/constants.js +25 -0
- package/v2Components/CapInAppCTA/index.js +281 -0
- package/v2Components/CapInAppCTA/index.scss +93 -0
- package/v2Components/CapInAppCTA/messages.js +85 -0
- package/v2Components/MobilePushPreviewV2/index.js +81 -23
- package/v2Components/TemplatePreview/_templatePreview.scss +448 -0
- package/v2Components/TemplatePreview/assets/images/inapp_mobile_android_bottom.svg +11 -0
- package/v2Components/TemplatePreview/assets/images/inapp_mobile_android_full.svg +11 -0
- package/v2Components/TemplatePreview/assets/images/inapp_mobile_android_modal.svg +11 -0
- package/v2Components/TemplatePreview/assets/images/inapp_mobile_android_top.svg +11 -0
- package/v2Components/TemplatePreview/assets/images/inapp_mobile_ios_bottom.svg +6 -0
- package/v2Components/TemplatePreview/assets/images/inapp_mobile_ios_full.svg +18 -0
- package/v2Components/TemplatePreview/assets/images/inapp_mobile_ios_modal.svg +7 -0
- package/v2Components/TemplatePreview/assets/images/inapp_mobile_ios_top.svg +13 -0
- package/v2Components/TemplatePreview/index.js +660 -375
- package/v2Components/TemplatePreview/messages.js +4 -0
- package/v2Containers/App/constants.js +1 -0
- package/v2Containers/CreativesContainer/SlideBoxContent.js +43 -0
- package/v2Containers/CreativesContainer/SlideBoxHeader.js +4 -1
- package/v2Containers/CreativesContainer/constants.js +1 -0
- package/v2Containers/CreativesContainer/index.js +94 -27
- package/v2Containers/CreativesContainer/messages.js +4 -0
- package/v2Containers/InApp/actions.js +64 -0
- package/v2Containers/InApp/constants.js +95 -0
- package/v2Containers/InApp/index.js +745 -0
- package/v2Containers/InApp/index.scss +47 -0
- package/v2Containers/InApp/messages.js +86 -0
- package/v2Containers/InApp/reducer.js +109 -0
- package/v2Containers/InApp/sagas.js +143 -0
- package/v2Containers/InApp/selectors.js +12 -0
- package/v2Containers/InApp/tests/action.test.js +53 -0
- package/v2Containers/InApp/tests/index.test.js +152 -0
- package/v2Containers/InApp/tests/mockData.js +897 -0
- package/v2Containers/InApp/tests/reducer.test.js +177 -0
- package/v2Containers/InApp/tests/sagas.test.js +391 -0
- package/v2Containers/Templates/_templates.scss +7 -0
- package/v2Containers/Templates/index.js +103 -23
- package/v2Containers/Templates/messages.js +20 -0
- package/v2Containers/TemplatesV2/index.js +8 -2
- package/v2Containers/TemplatesV2/messages.js +4 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { injectIntl } from 'react-intl';
|
|
3
|
+
import { browserHistory } from 'react-router';
|
|
4
|
+
import '@testing-library/jest-dom';
|
|
5
|
+
import { Provider } from 'react-redux';
|
|
6
|
+
import configureStore from '../../../store';
|
|
7
|
+
import CapDeviceContent from '../index';
|
|
8
|
+
import { render, screen, fireEvent } from '../../../utils/test-utils';
|
|
9
|
+
import { deviceContentProps } from '../../../v2Containers/InApp/tests/mockData';
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
let store;
|
|
13
|
+
beforeAll(() => {
|
|
14
|
+
store = configureStore({}, browserHistory);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
const ComponentToRender = injectIntl(CapDeviceContent);
|
|
18
|
+
const renderComponent = (props) =>
|
|
19
|
+
render(
|
|
20
|
+
<Provider store={store}>
|
|
21
|
+
<ComponentToRender {...props} />
|
|
22
|
+
</Provider>,
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
describe('Test CapDeviceContent', () => {
|
|
26
|
+
it('test case for CapDeviceContent component Android pane', async () => {
|
|
27
|
+
renderComponent(deviceContentProps);
|
|
28
|
+
const msgBox = screen.getAllByPlaceholderText(/Please input in-app notification message content/i);
|
|
29
|
+
fireEvent.change(msgBox[0], 'val');
|
|
30
|
+
const copyLink = screen.getByRole('link', {
|
|
31
|
+
name: /copy title and content from ios/i,
|
|
32
|
+
});
|
|
33
|
+
fireEvent.click(copyLink);
|
|
34
|
+
expect(copyLink).toBeInTheDocument();
|
|
35
|
+
});
|
|
36
|
+
it('test case for CapDeviceContent component Ios pane', () => {
|
|
37
|
+
renderComponent(
|
|
38
|
+
{...deviceContentProps,
|
|
39
|
+
panes: "iOS",
|
|
40
|
+
buttonType: 'CTA',
|
|
41
|
+
setTemplateMediaType: jest.fn(),
|
|
42
|
+
setButtonType: jest.fn(),
|
|
43
|
+
setCtaData: jest.fn(),
|
|
44
|
+
setTemplateMessage: jest.fn(),
|
|
45
|
+
setTemplateMessageError: jest.fn(),
|
|
46
|
+
setTitle: jest.fn(),
|
|
47
|
+
templateMediType: 'IMAGE',
|
|
48
|
+
addActionLink: true,
|
|
49
|
+
ctaData: [
|
|
50
|
+
{
|
|
51
|
+
index: 0,
|
|
52
|
+
ctaType: "WEBSITE",
|
|
53
|
+
text: "test",
|
|
54
|
+
urlType: "DEEP_LINK",
|
|
55
|
+
url: "",
|
|
56
|
+
isSaved: true,
|
|
57
|
+
label: "Test_1",
|
|
58
|
+
},
|
|
59
|
+
] });
|
|
60
|
+
const msgBox = screen.getAllByPlaceholderText(/Please input in-app notification message content/i);
|
|
61
|
+
msgBox[0].focus();
|
|
62
|
+
fireEvent.change(msgBox[0], { target: {value: 'val'}});
|
|
63
|
+
fireEvent.change(msgBox[0], { target: {value: ''}});
|
|
64
|
+
const titleBox = screen.getAllByPlaceholderText(/Please input message title name/i);
|
|
65
|
+
titleBox[0].focus();
|
|
66
|
+
fireEvent.change(titleBox[0], { target: {value: 'val'}});
|
|
67
|
+
const img = screen.getByText(/image/i);
|
|
68
|
+
fireEvent.click(img);
|
|
69
|
+
const none = screen.getByText(/None/i);
|
|
70
|
+
fireEvent.click(none);
|
|
71
|
+
const editIcon = screen.getByText(/Test_1/i).nextSibling.firstChild;
|
|
72
|
+
fireEvent.click(editIcon);
|
|
73
|
+
expect(screen.getByText(/Test_1/i)).toBeInTheDocument();
|
|
74
|
+
});
|
|
75
|
+
});
|
|
@@ -20,7 +20,7 @@ import { injectIntl, FormattedMessage, intlShape} from 'react-intl';
|
|
|
20
20
|
import { isEmpty, get } from 'lodash';
|
|
21
21
|
import './index.scss';
|
|
22
22
|
import Gallery from '../../v2Containers/Assets/Gallery';
|
|
23
|
-
import { FACEBOOK, RCS, WHATSAPP } from "../../v2Containers/CreativesContainer/constants";
|
|
23
|
+
import { FACEBOOK, INAPP, RCS, WHATSAPP } from "../../v2Containers/CreativesContainer/constants";
|
|
24
24
|
|
|
25
25
|
import messages from './messages';
|
|
26
26
|
function CapImageUpload(props) {
|
|
@@ -252,7 +252,7 @@ function CapImageUpload(props) {
|
|
|
252
252
|
</CapHeadingSpan>
|
|
253
253
|
</>
|
|
254
254
|
)}
|
|
255
|
-
{channel
|
|
255
|
+
{![WHATSAPP, INAPP].includes(channel) && (
|
|
256
256
|
<CapHeadingSpan type="label2" className="image-dimension">
|
|
257
257
|
<FormattedMessage {...messages.imageDimenstionDescription} values={{ width: imgWidth, height: imgHeight }} />
|
|
258
258
|
</CapHeadingSpan>
|
|
@@ -267,8 +267,15 @@ function CapImageUpload(props) {
|
|
|
267
267
|
<FormattedMessage {...messages.imageSize} />
|
|
268
268
|
</CapHeadingSpan>
|
|
269
269
|
)}
|
|
270
|
+
{
|
|
271
|
+
channel === INAPP && (
|
|
272
|
+
<CapHeadingSpan type="label2" className="image-size">
|
|
273
|
+
<FormattedMessage {...messages.whatsappImageSize} />
|
|
274
|
+
</CapHeadingSpan>
|
|
275
|
+
)
|
|
276
|
+
}
|
|
270
277
|
<CapHeadingSpan type="label2" className="image-format">
|
|
271
|
-
<FormattedMessage {...messages.format} />
|
|
278
|
+
{channel === INAPP ? <FormattedMessage {...messages.format2} /> : <FormattedMessage {...messages.format} />}
|
|
272
279
|
</CapHeadingSpan>
|
|
273
280
|
</div>
|
|
274
281
|
</div>
|
|
@@ -42,6 +42,10 @@ export default defineMessages({
|
|
|
42
42
|
id: `${scope}.format`,
|
|
43
43
|
defaultMessage: 'Format: JPEG, JPG, PNG',
|
|
44
44
|
},
|
|
45
|
+
format2: {
|
|
46
|
+
id: `${scope}.format2`,
|
|
47
|
+
defaultMessage: 'Format: png, jpg, jpeg',
|
|
48
|
+
},
|
|
45
49
|
imageErrorDesc: {
|
|
46
50
|
id: `${scope}.imageErrorDesc`,
|
|
47
51
|
defaultMessage:
|
|
@@ -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_LINK = 'EXTERNAL_LINK';
|
|
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_LINK,
|
|
18
|
+
value: EXTERNAL_LINK,
|
|
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,281 @@
|
|
|
1
|
+
import React, { useState } 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 CapTooltipWithInfo from "@capillarytech/cap-ui-library/CapTooltipWithInfo";
|
|
14
|
+
import CapSelect from "@capillarytech/cap-ui-library/CapSelect";
|
|
15
|
+
import CapTag from '@capillarytech/cap-ui-library/CapTag';
|
|
16
|
+
import { CAP_SPACE_04 } from "@capillarytech/cap-ui-library/styled/variables";
|
|
17
|
+
import globalMessages from "../../v2Containers/Cap/messages";
|
|
18
|
+
import inAppMsg from "../../v2Containers/InApp/messages";
|
|
19
|
+
import messages from "./messages";
|
|
20
|
+
import './index.scss';
|
|
21
|
+
import {
|
|
22
|
+
isUrl,
|
|
23
|
+
isValidText,
|
|
24
|
+
} from "../../v2Containers/Line/Container/Wrapper/utils";
|
|
25
|
+
import {
|
|
26
|
+
BTN_MAX_LENGTH,
|
|
27
|
+
DEEP_LINK,
|
|
28
|
+
EXTERNAL_LINK,
|
|
29
|
+
CTA_OPTIONS,
|
|
30
|
+
URL_MAX_LENGTH,
|
|
31
|
+
} from "./constants";
|
|
32
|
+
|
|
33
|
+
export const CapInAppCTA = (props) => {
|
|
34
|
+
const {
|
|
35
|
+
intl,
|
|
36
|
+
ctaData = [],
|
|
37
|
+
updateHandler,
|
|
38
|
+
deleteHandler,
|
|
39
|
+
isEditFlow,
|
|
40
|
+
deepLink,
|
|
41
|
+
} = props;
|
|
42
|
+
const { formatMessage } = intl;
|
|
43
|
+
|
|
44
|
+
const [urlError, setUrlError] = useState(false);
|
|
45
|
+
const [buttonError, setButtonError] = useState(false);
|
|
46
|
+
const [ctaDeepLinkValue, setCtaDeepLinkValue] = useState("");
|
|
47
|
+
|
|
48
|
+
const updateHelper = (type, value, index) => {
|
|
49
|
+
let clonedCta = cloneDeep(ctaData[index]);
|
|
50
|
+
clonedCta = {
|
|
51
|
+
...clonedCta,
|
|
52
|
+
[type]: value,
|
|
53
|
+
};
|
|
54
|
+
updateHandler(clonedCta, index);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const renderLength = (len, max) => (
|
|
58
|
+
<CapHeading
|
|
59
|
+
type="label1"
|
|
60
|
+
className="inapp-render-btn-length"
|
|
61
|
+
>
|
|
62
|
+
{formatMessage(inAppMsg.templateMessageLength, {
|
|
63
|
+
currentLength: len,
|
|
64
|
+
maxLength: max,
|
|
65
|
+
})}
|
|
66
|
+
</CapHeading>
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
const onButtonTextChange = ({ target }) => {
|
|
71
|
+
const { value, id } = target;
|
|
72
|
+
let errorMessage = "";
|
|
73
|
+
if (!isValidText(value)) {
|
|
74
|
+
errorMessage = formatMessage(messages.ctaButtonErrorMessage);
|
|
75
|
+
}
|
|
76
|
+
setButtonError(errorMessage);
|
|
77
|
+
updateHelper("text", value, id);
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const onUrlTypeChange = (value, index) => {
|
|
81
|
+
updateHelper('urlType', value, index);
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const onUrlChange = ({ target }) => {
|
|
85
|
+
const { value} = target;
|
|
86
|
+
let errorMessage = false;
|
|
87
|
+
if (!isUrl(value)) {
|
|
88
|
+
errorMessage = formatMessage(messages.ctaWebsiteUrlErrorMessage);
|
|
89
|
+
}
|
|
90
|
+
setUrlError(errorMessage);
|
|
91
|
+
updateHelper('url', value, 0); // 0 is an index
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const onDeepLinkSelect = (value) => {
|
|
95
|
+
setCtaDeepLinkValue(value);
|
|
96
|
+
let errorMessage = false;
|
|
97
|
+
if (!isUrl(value.key)) {
|
|
98
|
+
errorMessage = formatMessage(messages.ctaWebsiteUrlErrorMessage);
|
|
99
|
+
}
|
|
100
|
+
setUrlError(errorMessage);
|
|
101
|
+
updateHelper('url', value.key, 0); // 0 is an index
|
|
102
|
+
updateHelper('label', value.label, 0); // 0 is an index
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const ctaSaveDisabled = (index) => {
|
|
106
|
+
const { urlType, text, url } = ctaData[index] || {};
|
|
107
|
+
if (text === "" || buttonError) {
|
|
108
|
+
return true;
|
|
109
|
+
} else if (urlType === DEEP_LINK && (ctaDeepLinkValue === "" || urlError)) {
|
|
110
|
+
return true;
|
|
111
|
+
} else if (urlType === EXTERNAL_LINK && (url === "" || urlError)) {
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const isSavedCta = (index, saved) => {
|
|
117
|
+
updateHelper("isSaved", saved, index);
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
const renderedContent = () => {
|
|
121
|
+
const renderArray = [];
|
|
122
|
+
ctaData?.forEach((cta) => {
|
|
123
|
+
const { index, text, url, urlType, isSaved, label } = cta || {};
|
|
124
|
+
//this is to display buttons after they are saved, in both create and edit mode.
|
|
125
|
+
if (isSaved) {
|
|
126
|
+
renderArray.push(
|
|
127
|
+
<CapRow
|
|
128
|
+
className="cap-inapp-saved-cta"
|
|
129
|
+
align="middle"
|
|
130
|
+
type="flex"
|
|
131
|
+
>
|
|
132
|
+
<CapRow className="inapp-cta-row">
|
|
133
|
+
<CapColumn>
|
|
134
|
+
<CapIcon size="s" type={'launch'} />
|
|
135
|
+
</CapColumn>
|
|
136
|
+
<CapColumn>
|
|
137
|
+
<CapLabel type="label2" className="inapp-saved-cta-button-text">
|
|
138
|
+
{text}
|
|
139
|
+
</CapLabel>
|
|
140
|
+
</CapColumn>
|
|
141
|
+
</CapRow>
|
|
142
|
+
<CapColumn >
|
|
143
|
+
{urlType === DEEP_LINK ?
|
|
144
|
+
<CapTag className="cta-type-label">{formatMessage(messages.urlDeepLink)}</CapTag>
|
|
145
|
+
: <CapTag className="cta-type-label">{formatMessage(messages.urlExternalLink)}</CapTag>}
|
|
146
|
+
</CapColumn>
|
|
147
|
+
<CapColumn>
|
|
148
|
+
{urlType === DEEP_LINK ? label : ''}
|
|
149
|
+
</CapColumn>
|
|
150
|
+
{(
|
|
151
|
+
<CapRow className="cta-action-grp">
|
|
152
|
+
<CapColumn
|
|
153
|
+
className="inapp-saved-cta-edit-icon"
|
|
154
|
+
onClick={() => isSavedCta(index, false)}
|
|
155
|
+
>
|
|
156
|
+
<CapIcon size="s" type="edit" className="cta-action" />
|
|
157
|
+
</CapColumn>
|
|
158
|
+
<CapColumn onClick={() => deleteHandler(index)} className="cta-del-icon">
|
|
159
|
+
<CapIcon size="s" type="delete" className="cta-action" ariaLabel="delete-cta-icon" />
|
|
160
|
+
</CapColumn>
|
|
161
|
+
</CapRow>
|
|
162
|
+
)}
|
|
163
|
+
</CapRow>
|
|
164
|
+
);
|
|
165
|
+
} else {
|
|
166
|
+
//this is to display buttons before they are saved, only in create mode.
|
|
167
|
+
renderArray.push(
|
|
168
|
+
<CapRow
|
|
169
|
+
className="cap-inapp-cta"
|
|
170
|
+
id={`cap-inapp-cta-${index}`}
|
|
171
|
+
>
|
|
172
|
+
<CapRow className="inapp-cta-buttons">
|
|
173
|
+
<CapColumn span={12} >
|
|
174
|
+
{/* Type of link */}
|
|
175
|
+
<CapHeading type="h4" className="cta-label">
|
|
176
|
+
{formatMessage(messages.ctaType)}
|
|
177
|
+
</CapHeading>
|
|
178
|
+
<CapSelect
|
|
179
|
+
id="inapp-cta-type"
|
|
180
|
+
options={CTA_OPTIONS || []}
|
|
181
|
+
onChange={(value) => onUrlTypeChange(value, index)}
|
|
182
|
+
value={urlType}
|
|
183
|
+
/>
|
|
184
|
+
</CapColumn>
|
|
185
|
+
<CapColumn span={12}>
|
|
186
|
+
{/* Button text */}
|
|
187
|
+
<CapHeading type="h4" className="cta-label">
|
|
188
|
+
{formatMessage(messages.ctaButtonText)}
|
|
189
|
+
<CapTooltipWithInfo
|
|
190
|
+
infoIconProps={{
|
|
191
|
+
style: { marginLeft: CAP_SPACE_04 },
|
|
192
|
+
}}
|
|
193
|
+
autoAdjustOverflow
|
|
194
|
+
placement="right"
|
|
195
|
+
title={formatMessage(messages.ctaButtonTextTooltip)}
|
|
196
|
+
/>
|
|
197
|
+
</CapHeading>
|
|
198
|
+
<CapInput
|
|
199
|
+
id={index}
|
|
200
|
+
className="inapp-cta-button-text"
|
|
201
|
+
onChange={onButtonTextChange}
|
|
202
|
+
placeholder={formatMessage(messages.ctaButtonTextPlaceholder)}
|
|
203
|
+
value={text}
|
|
204
|
+
size="large"
|
|
205
|
+
maxLength={BTN_MAX_LENGTH}
|
|
206
|
+
errorMessage={buttonError}
|
|
207
|
+
/>
|
|
208
|
+
{renderLength(text.length, BTN_MAX_LENGTH)}
|
|
209
|
+
</CapColumn>
|
|
210
|
+
</CapRow>
|
|
211
|
+
{urlType === DEEP_LINK && (
|
|
212
|
+
<>
|
|
213
|
+
<CapHeading type="h4">
|
|
214
|
+
{formatMessage(messages.urlDeepLink)}
|
|
215
|
+
</CapHeading>
|
|
216
|
+
<CapSelect
|
|
217
|
+
id="inapp-deep-link-type"
|
|
218
|
+
placeholder={formatMessage(messages.ctaDeepLinkOptionsPlaceholder)}
|
|
219
|
+
options={deepLink || []}
|
|
220
|
+
onChange={onDeepLinkSelect}
|
|
221
|
+
value={ctaDeepLinkValue}
|
|
222
|
+
labelInValue
|
|
223
|
+
/>
|
|
224
|
+
</>
|
|
225
|
+
|
|
226
|
+
)}
|
|
227
|
+
{urlType === EXTERNAL_LINK && (
|
|
228
|
+
<>
|
|
229
|
+
<CapHeading type="h4">
|
|
230
|
+
{formatMessage(messages.urlExternalLink)}
|
|
231
|
+
</CapHeading>
|
|
232
|
+
<CapInput
|
|
233
|
+
id="inapp-cta-external-link"
|
|
234
|
+
className="inapp-cta-external-link"
|
|
235
|
+
onChange={onUrlChange}
|
|
236
|
+
placeholder={formatMessage(messages.ctaExternalLinkPlaceholder)}
|
|
237
|
+
value={url}
|
|
238
|
+
size="large"
|
|
239
|
+
maxLength={URL_MAX_LENGTH}
|
|
240
|
+
errorMessage={urlError}
|
|
241
|
+
/>
|
|
242
|
+
</>
|
|
243
|
+
)}
|
|
244
|
+
<CapRow className="inapp-cta-save-delete-btn">
|
|
245
|
+
<CapTooltip
|
|
246
|
+
title={
|
|
247
|
+
ctaSaveDisabled(index)
|
|
248
|
+
? formatMessage(messages.ctaSaveDisabled)
|
|
249
|
+
: ""
|
|
250
|
+
}
|
|
251
|
+
placement={"bottom"}
|
|
252
|
+
>
|
|
253
|
+
<div className="button-disabled-tooltip-wrapper">
|
|
254
|
+
<CapButton
|
|
255
|
+
onClick={() => isSavedCta(index, true)}
|
|
256
|
+
disabled={ctaSaveDisabled(index)}
|
|
257
|
+
className="inapp-cta-save-btn"
|
|
258
|
+
>
|
|
259
|
+
{formatMessage(globalMessages.save)}
|
|
260
|
+
</CapButton>
|
|
261
|
+
</div>
|
|
262
|
+
</CapTooltip>
|
|
263
|
+
<CapButton
|
|
264
|
+
onClick={() => deleteHandler(index)}
|
|
265
|
+
className="inapp-cta-delete-btn"
|
|
266
|
+
type="secondary"
|
|
267
|
+
>
|
|
268
|
+
{formatMessage(globalMessages.delete)}
|
|
269
|
+
</CapButton>
|
|
270
|
+
</CapRow>
|
|
271
|
+
</CapRow>
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
return renderArray;
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
return renderedContent();
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
export default injectIntl(CapInAppCTA);
|
|
@@ -0,0 +1,93 @@
|
|
|
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
|
+
|
|
13
|
+
#inapp-cta-type {
|
|
14
|
+
width: 95%;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.inapp-cta-button-text {
|
|
18
|
+
width: 95%;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.inapp-render-btn-length {
|
|
22
|
+
margin-top: $CAP_SPACE_12;
|
|
23
|
+
width: 90%;
|
|
24
|
+
margin-left: 52%;
|
|
25
|
+
margin-bottom: $CAP_SPACE_12;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
#inapp-deep-link-type {
|
|
30
|
+
width: 100%;
|
|
31
|
+
margin-top: $CAP_SPACE_12;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.inapp-cta-external-link {
|
|
35
|
+
margin-top: $CAP_SPACE_12;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.inapp-cta-save-delete-btn {
|
|
39
|
+
margin-top: $CAP_SPACE_16;
|
|
40
|
+
|
|
41
|
+
.inapp-cta-save-btn {
|
|
42
|
+
margin-right: $CAP_SPACE_04;
|
|
43
|
+
}
|
|
44
|
+
.inapp-cta-delete-btn {
|
|
45
|
+
margin-left: $CAP_SPACE_04;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.cap-inapp-saved-cta {
|
|
52
|
+
border: solid 1px $CAP_G06;
|
|
53
|
+
margin-left: $CAP_SPACE_20;
|
|
54
|
+
display: flex;
|
|
55
|
+
justify-content: space-between;
|
|
56
|
+
padding: $CAP_SPACE_08 $CAP_SPACE_12;
|
|
57
|
+
border-radius: $CAP_SPACE_04;
|
|
58
|
+
margin-top: $CAP_SPACE_12;
|
|
59
|
+
height: $CAP_SPACE_40;
|
|
60
|
+
|
|
61
|
+
.inapp-saved-cta-button-text {
|
|
62
|
+
font-weight: 500;
|
|
63
|
+
padding-left: '15px'
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.inapp-saved-cta-edit-icon {
|
|
67
|
+
margin-left: 4.286rem;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
.cta-label {
|
|
71
|
+
margin-bottom: $CAP_SPACE_08;
|
|
72
|
+
}
|
|
73
|
+
.cta-type-label {
|
|
74
|
+
border-radius: 1rem;
|
|
75
|
+
background-color: $CAP_G08;
|
|
76
|
+
width: $CAP_SPACE_80;
|
|
77
|
+
height: $CAP_SPACE_24 !important;
|
|
78
|
+
align-items: center;
|
|
79
|
+
justify-content: center;
|
|
80
|
+
}
|
|
81
|
+
.cta-action {
|
|
82
|
+
cursor: pointer;
|
|
83
|
+
}
|
|
84
|
+
.inapp-cta-row {
|
|
85
|
+
display: flex;
|
|
86
|
+
align-items: center;
|
|
87
|
+
}
|
|
88
|
+
.cta-action-grp {
|
|
89
|
+
display: flex;
|
|
90
|
+
}
|
|
91
|
+
.cta-del-icon {
|
|
92
|
+
padding-left: 1rem;
|
|
93
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { defineMessages } from 'react-intl';
|
|
2
|
+
const prefix = `creatives.componentsV2.CapInAppCTA`;
|
|
3
|
+
export default defineMessages({
|
|
4
|
+
ctaType: {
|
|
5
|
+
id: `${prefix}.ctaType`,
|
|
6
|
+
defaultMessage: 'Type of link',
|
|
7
|
+
},
|
|
8
|
+
urlDeepLink: {
|
|
9
|
+
id: `${prefix}.urlDeepLink`,
|
|
10
|
+
defaultMessage: 'Deep link',
|
|
11
|
+
},
|
|
12
|
+
urlExternalLink: {
|
|
13
|
+
id: `${prefix}.urlExternalLink`,
|
|
14
|
+
defaultMessage: 'External link',
|
|
15
|
+
},
|
|
16
|
+
ctaButtonText: {
|
|
17
|
+
id: `${prefix}.ctaButtonText`,
|
|
18
|
+
defaultMessage: 'Button text',
|
|
19
|
+
},
|
|
20
|
+
ctaDeepLinkOptionsPlaceholder: {
|
|
21
|
+
id: `${prefix}.ctaDeepLinkOptionsPlaceholder`,
|
|
22
|
+
defaultMessage: 'Select deep link',
|
|
23
|
+
},
|
|
24
|
+
ctaExternalLinkPlaceholder: {
|
|
25
|
+
id: `${prefix}.ctaExternalLinkPlaceholder`,
|
|
26
|
+
defaultMessage: 'Enter the external link',
|
|
27
|
+
},
|
|
28
|
+
ctaButtonTextPlaceholder: {
|
|
29
|
+
id: `${prefix}.ctaButtonTextPlaceholder`,
|
|
30
|
+
defaultMessage: 'Enter button text',
|
|
31
|
+
},
|
|
32
|
+
ctaWebsiteType: {
|
|
33
|
+
id: `${prefix}.ctaWebsiteType`,
|
|
34
|
+
defaultMessage: 'URL Type',
|
|
35
|
+
},
|
|
36
|
+
ctaLinkTypeDeep: {
|
|
37
|
+
id: `${prefix}.ctaLinkTypeDeep`,
|
|
38
|
+
defaultMessage: 'Deep link',
|
|
39
|
+
},
|
|
40
|
+
ctaLinkTypeExternal: {
|
|
41
|
+
id: `${prefix}.ctaLinkTypeExternal`,
|
|
42
|
+
defaultMessage: 'External link',
|
|
43
|
+
},
|
|
44
|
+
ctaWebsiteUrl: {
|
|
45
|
+
id: `${prefix}.ctaWebsiteUrl`,
|
|
46
|
+
defaultMessage: 'Website URL',
|
|
47
|
+
},
|
|
48
|
+
ctaStaticPlaceholder: {
|
|
49
|
+
id: `${prefix}.ctaStaticPlaceholder`,
|
|
50
|
+
defaultMessage: 'Enter website URL',
|
|
51
|
+
},
|
|
52
|
+
ctaWebsiteUrlErrorMessage: {
|
|
53
|
+
id: `${prefix}.ctaWebsiteUrlErrorMessage`,
|
|
54
|
+
defaultMessage: 'URL is not valid',
|
|
55
|
+
},
|
|
56
|
+
ctaButtonErrorMessage: {
|
|
57
|
+
id: `${prefix}.ctaButtonErrorMessage`,
|
|
58
|
+
defaultMessage: "Newlines, Emojis, or Special characters are not allowed",
|
|
59
|
+
},
|
|
60
|
+
ctaSaveDisabled: {
|
|
61
|
+
id: `${prefix}.ctaSaveDisabled`,
|
|
62
|
+
defaultMessage: 'Please complete the above fields to enable button',
|
|
63
|
+
},
|
|
64
|
+
ctaButtonTextTooltip: {
|
|
65
|
+
id: `${prefix}.ctaButtonTextTooltip`,
|
|
66
|
+
defaultMessage:
|
|
67
|
+
'Use this to name the button. We would recommend not to use special characters for the button text.',
|
|
68
|
+
},
|
|
69
|
+
ctaOptionDisabledTooltipDeepLink: {
|
|
70
|
+
id: `${prefix}.ctaOptionDisabledTooltipDeepLink`,
|
|
71
|
+
defaultMessage: 'A page within the mobile app',
|
|
72
|
+
},
|
|
73
|
+
ctaOptionDisabledTooltipExternalLink: {
|
|
74
|
+
id: `${prefix}.ctaOptionDisabledTooltipExternalLink`,
|
|
75
|
+
defaultMessage: 'An external web page',
|
|
76
|
+
},
|
|
77
|
+
staticUrlWithVarErrorMessage: {
|
|
78
|
+
id: `${prefix}.staticUrlWithVarErrorMessage`,
|
|
79
|
+
defaultMessage: 'Button with url type as static cannot contain variables',
|
|
80
|
+
},
|
|
81
|
+
useTwoBracketsOnly: {
|
|
82
|
+
id: `${prefix}.useTwoBracketsOnly`,
|
|
83
|
+
defaultMessage: 'Use two brackets on each side to declare a variable',
|
|
84
|
+
},
|
|
85
|
+
});
|