@capillarytech/creatives-library 8.0.239-alpha.0 → 8.0.239
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/services/api.js +0 -5
- package/translations/en.json +0 -1
- package/utils/transformerUtils.js +0 -42
- package/v2Components/CapImageUpload/constants.js +0 -2
- package/v2Components/CapImageUpload/index.js +14 -54
- package/v2Components/CapImageUpload/index.scss +1 -4
- package/v2Components/CapImageUpload/messages.js +0 -4
- package/v2Containers/App/constants.js +0 -5
- package/v2Containers/Cap/tests/__snapshots__/index.test.js.snap +0 -1
- package/v2Containers/CreativesContainer/SlideBoxContent.js +2 -57
- package/v2Containers/CreativesContainer/SlideBoxHeader.js +0 -1
- package/v2Containers/CreativesContainer/constants.js +0 -2
- package/v2Containers/CreativesContainer/index.js +0 -152
- package/v2Containers/CreativesContainer/messages.js +0 -4
- package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/content.test.js.snap +0 -3
- package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/index.test.js.snap +0 -2
- package/v2Containers/Line/Container/Wrapper/tests/__snapshots__/index.test.js.snap +0 -25
- package/v2Containers/Line/Container/tests/__snapshots__/index.test.js.snap +0 -18
- package/v2Containers/Rcs/index.js +153 -383
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +0 -46
- package/v2Containers/Rcs/tests/index.test.js +168 -0
- package/v2Containers/SmsTrai/Create/tests/__snapshots__/index.test.js.snap +0 -4
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +0 -8
- package/v2Containers/Templates/ChannelTypeIllustration.js +1 -13
- package/v2Containers/Templates/_templates.scss +0 -203
- package/v2Containers/Templates/actions.js +1 -2
- package/v2Containers/Templates/constants.js +0 -1
- package/v2Containers/Templates/index.js +30 -273
- package/v2Containers/Templates/messages.js +0 -24
- package/v2Containers/Templates/reducer.js +0 -2
- package/v2Containers/Templates/tests/index.test.js +0 -10
- package/v2Containers/TemplatesV2/index.js +2 -3
- package/v2Containers/TemplatesV2/messages.js +0 -4
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +0 -132
- package/v2Components/CapImageUrlUpload/constants.js +0 -19
- package/v2Components/CapImageUrlUpload/index.js +0 -455
- package/v2Components/CapImageUrlUpload/index.scss +0 -35
- package/v2Components/CapImageUrlUpload/messages.js +0 -47
- package/v2Containers/WebPush/Create/components/ButtonForm.js +0 -175
- package/v2Containers/WebPush/Create/components/ButtonItem.js +0 -101
- package/v2Containers/WebPush/Create/components/ButtonList.js +0 -144
- package/v2Containers/WebPush/Create/components/_buttons.scss +0 -246
- package/v2Containers/WebPush/Create/components/tests/ButtonForm.test.js +0 -554
- package/v2Containers/WebPush/Create/components/tests/ButtonItem.test.js +0 -607
- package/v2Containers/WebPush/Create/components/tests/ButtonList.test.js +0 -633
- package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonForm.test.js.snap +0 -666
- package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonItem.test.js.snap +0 -74
- package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonList.test.js.snap +0 -80
- package/v2Containers/WebPush/Create/index.js +0 -1727
- package/v2Containers/WebPush/Create/index.scss +0 -123
- package/v2Containers/WebPush/Create/messages.js +0 -199
- package/v2Containers/WebPush/Create/preview/DevicePreviewContent.js +0 -241
- package/v2Containers/WebPush/Create/preview/NotificationContainer.js +0 -290
- package/v2Containers/WebPush/Create/preview/PreviewContent.js +0 -81
- package/v2Containers/WebPush/Create/preview/PreviewControls.js +0 -240
- package/v2Containers/WebPush/Create/preview/PreviewDisclaimer.js +0 -23
- package/v2Containers/WebPush/Create/preview/WebPushPreview.js +0 -139
- package/v2Containers/WebPush/Create/preview/assets/Light.svg +0 -53
- package/v2Containers/WebPush/Create/preview/assets/Top.svg +0 -5
- package/v2Containers/WebPush/Create/preview/assets/chrome-icon.png +0 -0
- package/v2Containers/WebPush/Create/preview/assets/edge-icon.png +0 -0
- package/v2Containers/WebPush/Create/preview/assets/firefox-icon.svg +0 -106
- package/v2Containers/WebPush/Create/preview/assets/iOS.svg +0 -26
- package/v2Containers/WebPush/Create/preview/assets/opera-icon.svg +0 -18
- package/v2Containers/WebPush/Create/preview/assets/safari-icon.svg +0 -29
- package/v2Containers/WebPush/Create/preview/components/AndroidMobileChromeHeader.js +0 -44
- package/v2Containers/WebPush/Create/preview/components/AndroidMobileExpanded.js +0 -110
- package/v2Containers/WebPush/Create/preview/components/IOSHeader.js +0 -45
- package/v2Containers/WebPush/Create/preview/components/NotificationExpandedContent.js +0 -72
- package/v2Containers/WebPush/Create/preview/components/NotificationHeader.js +0 -55
- package/v2Containers/WebPush/Create/preview/components/WindowsChromeExpanded.js +0 -70
- package/v2Containers/WebPush/Create/preview/components/tests/AndroidMobileExpanded.test.js +0 -512
- package/v2Containers/WebPush/Create/preview/components/tests/__snapshots__/AndroidMobileExpanded.test.js.snap +0 -77
- package/v2Containers/WebPush/Create/preview/config/notificationMappings.js +0 -527
- package/v2Containers/WebPush/Create/preview/constants.js +0 -162
- package/v2Containers/WebPush/Create/preview/notification-container.scss +0 -104
- package/v2Containers/WebPush/Create/preview/preview.scss +0 -409
- package/v2Containers/WebPush/Create/preview/styles/_android-mobile-chrome.scss +0 -300
- package/v2Containers/WebPush/Create/preview/styles/_android-mobile-edge.scss +0 -12
- package/v2Containers/WebPush/Create/preview/styles/_android-mobile-firefox.scss +0 -12
- package/v2Containers/WebPush/Create/preview/styles/_android-mobile-opera.scss +0 -12
- package/v2Containers/WebPush/Create/preview/styles/_android-tablet-chrome.scss +0 -303
- package/v2Containers/WebPush/Create/preview/styles/_android-tablet-edge.scss +0 -11
- package/v2Containers/WebPush/Create/preview/styles/_android-tablet-firefox.scss +0 -11
- package/v2Containers/WebPush/Create/preview/styles/_android-tablet-opera.scss +0 -11
- package/v2Containers/WebPush/Create/preview/styles/_base.scss +0 -188
- package/v2Containers/WebPush/Create/preview/styles/_ios.scss +0 -106
- package/v2Containers/WebPush/Create/preview/styles/_ipados.scss +0 -107
- package/v2Containers/WebPush/Create/preview/styles/_macos-chrome.scss +0 -75
- package/v2Containers/WebPush/Create/preview/styles/_windows-chrome.scss +0 -174
- package/v2Containers/WebPush/Create/preview/tests/DevicePreviewContent.test.js +0 -909
- package/v2Containers/WebPush/Create/preview/tests/NotificationContainer.test.js +0 -1077
- package/v2Containers/WebPush/Create/preview/tests/PreviewControls.test.js +0 -723
- package/v2Containers/WebPush/Create/preview/tests/WebPushPreview.test.js +0 -943
- package/v2Containers/WebPush/Create/preview/tests/__snapshots__/DevicePreviewContent.test.js.snap +0 -128
- package/v2Containers/WebPush/Create/preview/tests/__snapshots__/NotificationContainer.test.js.snap +0 -121
- package/v2Containers/WebPush/Create/preview/tests/__snapshots__/PreviewControls.test.js.snap +0 -144
- package/v2Containers/WebPush/Create/preview/tests/__snapshots__/WebPushPreview.test.js.snap +0 -127
- package/v2Containers/WebPush/Create/utils/urlValidation.js +0 -116
- package/v2Containers/WebPush/Create/utils/urlValidation.test.js +0 -449
- package/v2Containers/WebPush/actions.js +0 -60
- package/v2Containers/WebPush/constants.js +0 -108
- package/v2Containers/WebPush/index.js +0 -2
- package/v2Containers/WebPush/reducer.js +0 -104
- package/v2Containers/WebPush/sagas.js +0 -119
- package/v2Containers/WebPush/selectors.js +0 -65
- package/v2Containers/WebPush/tests/reducer.test.js +0 -863
- package/v2Containers/WebPush/tests/sagas.test.js +0 -566
- package/v2Containers/WebPush/tests/selectors.test.js +0 -843
|
@@ -1,1727 +0,0 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
useState,
|
|
3
|
-
useEffect,
|
|
4
|
-
useRef,
|
|
5
|
-
useCallback,
|
|
6
|
-
useMemo,
|
|
7
|
-
memo,
|
|
8
|
-
} from 'react';
|
|
9
|
-
import PropTypes from 'prop-types';
|
|
10
|
-
import { FormattedMessage, injectIntl, intlShape } from 'react-intl';
|
|
11
|
-
import { createStructuredSelector, createSelector } from 'reselect';
|
|
12
|
-
import { bindActionCreators } from 'redux';
|
|
13
|
-
import {
|
|
14
|
-
injectReducer,
|
|
15
|
-
injectSaga,
|
|
16
|
-
} from '@capillarytech/vulcan-react-sdk/utils';
|
|
17
|
-
import { DAEMON } from '@capillarytech/vulcan-react-sdk/utils/sagaInjectorTypes';
|
|
18
|
-
import CapInput from '@capillarytech/cap-ui-library/CapInput';
|
|
19
|
-
import CapRow from '@capillarytech/cap-ui-library/CapRow';
|
|
20
|
-
import CapColumn from '@capillarytech/cap-ui-library/CapColumn';
|
|
21
|
-
import CapHeading from '@capillarytech/cap-ui-library/CapHeading';
|
|
22
|
-
import CapDivider from '@capillarytech/cap-ui-library/CapDivider';
|
|
23
|
-
import CapSelect from '@capillarytech/cap-ui-library/CapSelect';
|
|
24
|
-
import CapError from '@capillarytech/cap-ui-library/CapError';
|
|
25
|
-
import CapButton from '@capillarytech/cap-ui-library/CapButton';
|
|
26
|
-
import CapRadioGroup from '@capillarytech/cap-ui-library/CapRadioGroup';
|
|
27
|
-
import CapLabel from '@capillarytech/cap-ui-library/CapLabel';
|
|
28
|
-
import CapImageUpload from '../../../v2Components/CapImageUpload';
|
|
29
|
-
import CapImageUrlUpload from '../../../v2Components/CapImageUrlUpload';
|
|
30
|
-
import TagList from '../../TagList';
|
|
31
|
-
import ButtonForm from './components/ButtonForm';
|
|
32
|
-
import ButtonList from './components/ButtonList';
|
|
33
|
-
import WebPushPreview from './preview/WebPushPreview';
|
|
34
|
-
import isEmpty from 'lodash/isEmpty';
|
|
35
|
-
import get from 'lodash/get';
|
|
36
|
-
import { WEBPUSH, WEBPUSH_BRAND_ICON } from '../../CreativesContainer/constants.js';
|
|
37
|
-
import {
|
|
38
|
-
WEBPUSH_MEDIA_TYPES,
|
|
39
|
-
WEBPUSH_MEDIA_TYPES_OPTIONS,
|
|
40
|
-
ALLOWED_IMAGE_EXTENSIONS_REGEX,
|
|
41
|
-
WEBPUSH_IMG_SIZE,
|
|
42
|
-
WEBPUSH_RECOMMENDED_DIMENSIONS,
|
|
43
|
-
BRAND_ICON_OPTIONS,
|
|
44
|
-
IMAGE_UPLOAD_METHODS,
|
|
45
|
-
WEBPUSH_BRAND_ICON_SIZE,
|
|
46
|
-
WEBPUSH_BRAND_ICON_RECOMMENDED_DIMENSIONS,
|
|
47
|
-
UPLOAD_FIELD_TYPES,
|
|
48
|
-
WEBPUSH_BUTTON_TYPES,
|
|
49
|
-
ON_CLICK_BEHAVIOUR_OPTIONS,
|
|
50
|
-
ACTION_TYPES,
|
|
51
|
-
} from '../constants';
|
|
52
|
-
import * as actions from '../actions';
|
|
53
|
-
import {
|
|
54
|
-
makeSelectWebPush,
|
|
55
|
-
makeSelectCreateError,
|
|
56
|
-
makeSelectCreateTemplateInProgress,
|
|
57
|
-
makeSelectEditTemplateInProgress,
|
|
58
|
-
makeSelectEditError,
|
|
59
|
-
} from '../selectors';
|
|
60
|
-
import webPushReducer from '../reducer';
|
|
61
|
-
import webPushSagas from '../sagas';
|
|
62
|
-
import withCreatives from '../../../hoc/withCreatives';
|
|
63
|
-
import messages from './messages';
|
|
64
|
-
import globalMessages from '../../Cap/messages';
|
|
65
|
-
import { isValidHttpUrl } from './utils/urlValidation';
|
|
66
|
-
import { validateTags } from '../../../utils/tagValidations';
|
|
67
|
-
import {
|
|
68
|
-
makeSelectMetaEntities,
|
|
69
|
-
setInjectedTags,
|
|
70
|
-
} from '../../Cap/selectors';
|
|
71
|
-
import {
|
|
72
|
-
ALL,
|
|
73
|
-
TAG,
|
|
74
|
-
EMBEDDED,
|
|
75
|
-
DEFAULT,
|
|
76
|
-
FULL,
|
|
77
|
-
LIBRARY,
|
|
78
|
-
} from '../../Whatsapp/constants';
|
|
79
|
-
import { SMS } from '../../CreativesContainer/constants';
|
|
80
|
-
import './index.scss';
|
|
81
|
-
|
|
82
|
-
// Character count configuration - set to false to disable
|
|
83
|
-
const SHOW_CHARACTER_COUNT = true;
|
|
84
|
-
|
|
85
|
-
// Maximum character limits for Web Push fields
|
|
86
|
-
const NOTIFICATION_TITLE_MAX_LENGTH = 65;
|
|
87
|
-
const MESSAGE_MAX_LENGTH = 240;
|
|
88
|
-
|
|
89
|
-
// Memoized TagList wrapper components for better performance
|
|
90
|
-
const MemoizedTagList = memo(({
|
|
91
|
-
moduleFilterEnabled,
|
|
92
|
-
label,
|
|
93
|
-
onContextChange,
|
|
94
|
-
location,
|
|
95
|
-
tags,
|
|
96
|
-
injectedTags,
|
|
97
|
-
selectedOfferDetails,
|
|
98
|
-
eventContextTags,
|
|
99
|
-
forwardedTags,
|
|
100
|
-
onTagSelect,
|
|
101
|
-
}) => (
|
|
102
|
-
<TagList
|
|
103
|
-
moduleFilterEnabled={moduleFilterEnabled}
|
|
104
|
-
label={label}
|
|
105
|
-
onContextChange={onContextChange}
|
|
106
|
-
location={location}
|
|
107
|
-
tags={tags}
|
|
108
|
-
injectedTags={injectedTags}
|
|
109
|
-
selectedOfferDetails={selectedOfferDetails}
|
|
110
|
-
eventContextTags={eventContextTags}
|
|
111
|
-
forwardedTags={forwardedTags}
|
|
112
|
-
onTagSelect={onTagSelect}
|
|
113
|
-
/>
|
|
114
|
-
), (prevProps, nextProps) => {
|
|
115
|
-
// Custom comparison function for better memoization
|
|
116
|
-
return (
|
|
117
|
-
prevProps.moduleFilterEnabled === nextProps.moduleFilterEnabled
|
|
118
|
-
&& prevProps.label === nextProps.label
|
|
119
|
-
&& prevProps.onContextChange === nextProps.onContextChange
|
|
120
|
-
&& prevProps.location === nextProps.location
|
|
121
|
-
&& prevProps.tags === nextProps.tags
|
|
122
|
-
&& prevProps.injectedTags === nextProps.injectedTags
|
|
123
|
-
&& prevProps.selectedOfferDetails === nextProps.selectedOfferDetails
|
|
124
|
-
&& prevProps.eventContextTags === nextProps.eventContextTags
|
|
125
|
-
&& prevProps.forwardedTags === nextProps.forwardedTags
|
|
126
|
-
&& prevProps.onTagSelect === nextProps.onTagSelect
|
|
127
|
-
);
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
MemoizedTagList.displayName = 'MemoizedTagList';
|
|
131
|
-
|
|
132
|
-
const createWebPushPayload = ({
|
|
133
|
-
templateName,
|
|
134
|
-
notificationTitle,
|
|
135
|
-
message,
|
|
136
|
-
mediaType,
|
|
137
|
-
accountId,
|
|
138
|
-
isFullMode,
|
|
139
|
-
imageSrc,
|
|
140
|
-
imageUrl,
|
|
141
|
-
imageUploadMethod,
|
|
142
|
-
brandIconOption,
|
|
143
|
-
brandIconSrc,
|
|
144
|
-
brandIconUrl,
|
|
145
|
-
buttons,
|
|
146
|
-
onClickBehaviour,
|
|
147
|
-
redirectUrl,
|
|
148
|
-
websiteLink,
|
|
149
|
-
}) => {
|
|
150
|
-
const trimmedTemplateName = (templateName || '').trim();
|
|
151
|
-
const trimmedTitle = (notificationTitle || '').trim();
|
|
152
|
-
const trimmedMessage = (message || '').trim();
|
|
153
|
-
|
|
154
|
-
const webpushContent = {
|
|
155
|
-
title: trimmedTitle,
|
|
156
|
-
message: trimmedMessage,
|
|
157
|
-
...(mediaType && mediaType !== WEBPUSH_MEDIA_TYPES.NONE ? { mediaType } : {}),
|
|
158
|
-
};
|
|
159
|
-
|
|
160
|
-
// Add image data if media type is IMAGE
|
|
161
|
-
if (mediaType === WEBPUSH_MEDIA_TYPES.IMAGE) {
|
|
162
|
-
if (imageUploadMethod === IMAGE_UPLOAD_METHODS.UPLOAD_IMAGE && imageSrc) {
|
|
163
|
-
webpushContent.image = imageSrc;
|
|
164
|
-
} else if (imageUploadMethod === IMAGE_UPLOAD_METHODS.ADD_IMAGE_URL && imageSrc) {
|
|
165
|
-
// Use imageSrc (uploaded secure_file_path) instead of imageUrl
|
|
166
|
-
// NOTE: To move upload to save event, check imageUrl exists but imageSrc is empty, upload, then use secure_file_path
|
|
167
|
-
webpushContent.image = imageSrc;
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
// Add brand icon data if option is not DONT_SHOW
|
|
172
|
-
if (brandIconOption !== BRAND_ICON_OPTIONS.DONT_SHOW && brandIconSrc) {
|
|
173
|
-
webpushContent.brandIcon = brandIconSrc;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
// Add on-click behaviour for the notification body
|
|
177
|
-
if (onClickBehaviour === ON_CLICK_BEHAVIOUR_OPTIONS.REDIRECT_TO_URL && redirectUrl) {
|
|
178
|
-
webpushContent.onClickAction = {
|
|
179
|
-
type: ACTION_TYPES.URL,
|
|
180
|
-
url: redirectUrl.trim(),
|
|
181
|
-
};
|
|
182
|
-
} else if (onClickBehaviour === ON_CLICK_BEHAVIOUR_OPTIONS.SITE_URL) {
|
|
183
|
-
webpushContent.onClickAction = {
|
|
184
|
-
type: ACTION_TYPES.SITE_URL,
|
|
185
|
-
url: websiteLink || '',
|
|
186
|
-
};
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// Add CTA buttons if any exist
|
|
190
|
-
if (buttons && buttons.length > 0) {
|
|
191
|
-
webpushContent.ctas = buttons.map((button) => ({
|
|
192
|
-
actionText: button.text,
|
|
193
|
-
type: ACTION_TYPES.URL,
|
|
194
|
-
actionLink: button.url,
|
|
195
|
-
}));
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
return {
|
|
199
|
-
name: trimmedTemplateName || "",
|
|
200
|
-
type: WEBPUSH,
|
|
201
|
-
definition: {
|
|
202
|
-
accountId,
|
|
203
|
-
},
|
|
204
|
-
versions: {
|
|
205
|
-
base: {
|
|
206
|
-
content: {
|
|
207
|
-
webpush: webpushContent,
|
|
208
|
-
},
|
|
209
|
-
},
|
|
210
|
-
},
|
|
211
|
-
};
|
|
212
|
-
};
|
|
213
|
-
|
|
214
|
-
const WebPushCreate = ({
|
|
215
|
-
isFullMode,
|
|
216
|
-
handleClose,
|
|
217
|
-
intl,
|
|
218
|
-
webPushActions,
|
|
219
|
-
createTemplateInProgress,
|
|
220
|
-
createTemplateError,
|
|
221
|
-
editTemplateInProgress,
|
|
222
|
-
editTemplateError,
|
|
223
|
-
accountData,
|
|
224
|
-
webPush,
|
|
225
|
-
onCreateComplete,
|
|
226
|
-
getFormData,
|
|
227
|
-
isGetFormData,
|
|
228
|
-
templateData,
|
|
229
|
-
creativesMode,
|
|
230
|
-
params,
|
|
231
|
-
globalActions,
|
|
232
|
-
location,
|
|
233
|
-
metaEntities,
|
|
234
|
-
injectedTags,
|
|
235
|
-
getDefaultTags,
|
|
236
|
-
supportedTags = [],
|
|
237
|
-
forwardedTags,
|
|
238
|
-
selectedOfferDetails = [],
|
|
239
|
-
eventContextTags = [],
|
|
240
|
-
}) => {
|
|
241
|
-
const { formatMessage } = intl;
|
|
242
|
-
const { CapHeadingSpan } = CapHeading;
|
|
243
|
-
// Convert to state for controlled components
|
|
244
|
-
const [templateName, setTemplateName] = useState('');
|
|
245
|
-
const [notificationTitle, setNotificationTitle] = useState('');
|
|
246
|
-
const [message, setMessage] = useState('');
|
|
247
|
-
const [mediaType, setMediaType] = useState(WEBPUSH_MEDIA_TYPES.NONE);
|
|
248
|
-
const [templateNameError, setTemplateNameError] = useState(false);
|
|
249
|
-
const [titleError, setTitleError] = useState('');
|
|
250
|
-
const [messageError, setMessageError] = useState('');
|
|
251
|
-
const [fieldCompletion, setFieldCompletion] = useState({
|
|
252
|
-
templateName: !isFullMode,
|
|
253
|
-
notificationTitle: false,
|
|
254
|
-
message: false,
|
|
255
|
-
});
|
|
256
|
-
const titleCountRef = useRef(null);
|
|
257
|
-
const messageCountRef = useRef(null);
|
|
258
|
-
// Track if save/edit was initiated to prevent stale response handlers from firing
|
|
259
|
-
const saveInitiatedRef = useRef(false);
|
|
260
|
-
const [brandIconOption, setBrandIconOption] = useState(BRAND_ICON_OPTIONS.DONT_SHOW);
|
|
261
|
-
const [onClickBehaviour, setOnClickBehaviour] = useState(ON_CLICK_BEHAVIOUR_OPTIONS.SITE_URL);
|
|
262
|
-
const [redirectUrl, setRedirectUrl] = useState('');
|
|
263
|
-
const [redirectUrlError, setRedirectUrlError] = useState('');
|
|
264
|
-
|
|
265
|
-
// Image upload state
|
|
266
|
-
const [imageUploadMethod, setImageUploadMethod] = useState(IMAGE_UPLOAD_METHODS.UPLOAD_IMAGE);
|
|
267
|
-
const [imageSrc, setImageSrc] = useState('');
|
|
268
|
-
const [imageUrl, setImageUrl] = useState('');
|
|
269
|
-
const [isImageValidating, setIsImageValidating] = useState(false);
|
|
270
|
-
const [isImageUploading, setIsImageUploading] = useState(false);
|
|
271
|
-
|
|
272
|
-
// Brand icon upload state
|
|
273
|
-
const [brandIconSrc, setBrandIconSrc] = useState('');
|
|
274
|
-
const [brandIconUrl, setBrandIconUrl] = useState('');
|
|
275
|
-
const [isBrandIconValidating, setIsBrandIconValidating] = useState(false);
|
|
276
|
-
const [isBrandIconUploading, setIsBrandIconUploading] = useState(false);
|
|
277
|
-
|
|
278
|
-
// Button state
|
|
279
|
-
const [buttons, setButtons] = useState([]);
|
|
280
|
-
const [isAddingButton, setIsAddingButton] = useState(false);
|
|
281
|
-
const [buttonBeingAdded, setButtonBeingAdded] = useState(null); // WEBPUSH_BUTTON_TYPES.PRIMARY or WEBPUSH_BUTTON_TYPES.SECONDARY
|
|
282
|
-
const [editingButtonIndex, setEditingButtonIndex] = useState(null);
|
|
283
|
-
const [activeUploadField, setActiveUploadField] = useState(null); // UPLOAD_FIELD_TYPES.IMAGE | UPLOAD_FIELD_TYPES.BRAND_ICON | null
|
|
284
|
-
const [tags, setTags] = useState([]);
|
|
285
|
-
const tagFetchKeyRef = useRef(null);
|
|
286
|
-
|
|
287
|
-
// Edit mode detection: check creativesMode or presence of template ID
|
|
288
|
-
const isEditMode = useMemo(
|
|
289
|
-
() =>
|
|
290
|
-
creativesMode === 'editTemplate'
|
|
291
|
-
|| creativesMode === 'edit'
|
|
292
|
-
|| !!(templateData?._id)
|
|
293
|
-
|| !!(params?.id),
|
|
294
|
-
[creativesMode, templateData?._id, params?.id],
|
|
295
|
-
);
|
|
296
|
-
|
|
297
|
-
const accountId = useMemo(() => {
|
|
298
|
-
const fallbackAccountId = get(templateData, 'definition.accountId');
|
|
299
|
-
return (
|
|
300
|
-
accountData?.accountId
|
|
301
|
-
|| accountData?.id
|
|
302
|
-
|| fallbackAccountId
|
|
303
|
-
|| get(accountData, 'sourceAccountIdentifier')
|
|
304
|
-
);
|
|
305
|
-
}, [
|
|
306
|
-
accountData?.accountId,
|
|
307
|
-
accountData?.id,
|
|
308
|
-
accountData?.sourceAccountIdentifier,
|
|
309
|
-
templateData,
|
|
310
|
-
]);
|
|
311
|
-
|
|
312
|
-
const websiteLink = useMemo(
|
|
313
|
-
() => accountData?.configs?.websiteLink || '',
|
|
314
|
-
[accountData?.configs?.websiteLink],
|
|
315
|
-
);
|
|
316
|
-
|
|
317
|
-
const previewUrl = useMemo(
|
|
318
|
-
() => (
|
|
319
|
-
onClickBehaviour === ON_CLICK_BEHAVIOUR_OPTIONS.REDIRECT_TO_URL
|
|
320
|
-
? redirectUrl
|
|
321
|
-
: websiteLink || redirectUrl
|
|
322
|
-
),
|
|
323
|
-
[onClickBehaviour, redirectUrl, websiteLink],
|
|
324
|
-
);
|
|
325
|
-
|
|
326
|
-
const brandIconOptions = useMemo(
|
|
327
|
-
() => ([
|
|
328
|
-
{ value: BRAND_ICON_OPTIONS.DONT_SHOW, label: formatMessage(messages.dontShow) },
|
|
329
|
-
{ value: BRAND_ICON_OPTIONS.UPLOAD_IMAGE, label: formatMessage(messages.uploadImage) },
|
|
330
|
-
{ value: BRAND_ICON_OPTIONS.ADD_IMAGE_URL, label: formatMessage(messages.addImageUrl) },
|
|
331
|
-
]),
|
|
332
|
-
[formatMessage],
|
|
333
|
-
);
|
|
334
|
-
|
|
335
|
-
const onClickBehaviourOptions = useMemo(
|
|
336
|
-
() => ([
|
|
337
|
-
{ value: ON_CLICK_BEHAVIOUR_OPTIONS.SITE_URL, label: formatMessage(messages.openSite) },
|
|
338
|
-
{ value: ON_CLICK_BEHAVIOUR_OPTIONS.REDIRECT_TO_URL, label: formatMessage(messages.redirectToSpecificUrl) },
|
|
339
|
-
]),
|
|
340
|
-
[formatMessage],
|
|
341
|
-
);
|
|
342
|
-
|
|
343
|
-
const validateTemplateName = useCallback((value) => !value || value.trim() === '', []);
|
|
344
|
-
|
|
345
|
-
const validateTitle = useCallback((value) => {
|
|
346
|
-
if (!value || value.trim() === '') {
|
|
347
|
-
return formatMessage(messages.titleRequired);
|
|
348
|
-
}
|
|
349
|
-
return '';
|
|
350
|
-
}, [formatMessage]);
|
|
351
|
-
|
|
352
|
-
const validateUrl = useCallback((value) => {
|
|
353
|
-
if (!value || value.trim() === '') {
|
|
354
|
-
return formatMessage(messages.urlRequired);
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
if (!isValidHttpUrl(value)) {
|
|
358
|
-
return formatMessage(messages.urlInvalid);
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
return '';
|
|
362
|
-
}, [formatMessage]);
|
|
363
|
-
|
|
364
|
-
const updateFieldCompletion = useCallback((field, hasValue) => {
|
|
365
|
-
setFieldCompletion((prev) => {
|
|
366
|
-
if (prev[field] === hasValue) {
|
|
367
|
-
return prev;
|
|
368
|
-
}
|
|
369
|
-
return {
|
|
370
|
-
...prev,
|
|
371
|
-
[field]: hasValue,
|
|
372
|
-
};
|
|
373
|
-
});
|
|
374
|
-
}, []);
|
|
375
|
-
|
|
376
|
-
const updateCharacterCount = useCallback((labelRef, currentLength, maxLength) => {
|
|
377
|
-
if (labelRef?.current) {
|
|
378
|
-
labelRef.current.textContent = formatMessage(messages.characterCount, {
|
|
379
|
-
currentLength,
|
|
380
|
-
maxLength,
|
|
381
|
-
});
|
|
382
|
-
}
|
|
383
|
-
}, [formatMessage]);
|
|
384
|
-
|
|
385
|
-
// Fetch tags on mount based on context
|
|
386
|
-
const locationType = location?.query?.type || '';
|
|
387
|
-
const locationModule = location?.query?.module || '';
|
|
388
|
-
|
|
389
|
-
const tagFetchKey = useMemo(
|
|
390
|
-
() => JSON.stringify({
|
|
391
|
-
type: locationType,
|
|
392
|
-
module: locationModule,
|
|
393
|
-
defaultTags: getDefaultTags || '',
|
|
394
|
-
}),
|
|
395
|
-
[locationModule, locationType, getDefaultTags],
|
|
396
|
-
);
|
|
397
|
-
|
|
398
|
-
useEffect(() => {
|
|
399
|
-
if (!globalActions?.fetchSchemaForEntity) return;
|
|
400
|
-
|
|
401
|
-
const { type, module } = location?.query || {};
|
|
402
|
-
const isEmbedded = type === EMBEDDED;
|
|
403
|
-
const context = isEmbedded ? module : DEFAULT;
|
|
404
|
-
const embedded = isEmbedded ? type : FULL;
|
|
405
|
-
const query = {
|
|
406
|
-
layout: SMS,
|
|
407
|
-
type: TAG,
|
|
408
|
-
context,
|
|
409
|
-
embedded,
|
|
410
|
-
};
|
|
411
|
-
if (getDefaultTags) {
|
|
412
|
-
query.context = getDefaultTags;
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
if (tagFetchKeyRef.current === tagFetchKey) {
|
|
416
|
-
return;
|
|
417
|
-
}
|
|
418
|
-
tagFetchKeyRef.current = tagFetchKey;
|
|
419
|
-
globalActions.fetchSchemaForEntity(query);
|
|
420
|
-
}, [globalActions, getDefaultTags, location?.query, tagFetchKey]);
|
|
421
|
-
|
|
422
|
-
// Update tags from metaEntities and supported tags
|
|
423
|
-
useEffect(() => {
|
|
424
|
-
if (!metaEntities) return;
|
|
425
|
-
let tagList = get(metaEntities, 'tags.standard', []);
|
|
426
|
-
if (locationType === EMBEDDED && locationModule === LIBRARY && !getDefaultTags) {
|
|
427
|
-
tagList = supportedTags;
|
|
428
|
-
}
|
|
429
|
-
setTags(tagList || []);
|
|
430
|
-
}, [metaEntities, locationModule, locationType, supportedTags, getDefaultTags]);
|
|
431
|
-
|
|
432
|
-
const handleOnTagsContextChange = useCallback((data) => {
|
|
433
|
-
const isEmbedded = locationType === EMBEDDED;
|
|
434
|
-
const embedded = isEmbedded ? locationType : FULL;
|
|
435
|
-
const context = (data || '').toLowerCase() === ALL ? DEFAULT : (data || '').toLowerCase();
|
|
436
|
-
const query = {
|
|
437
|
-
layout: SMS,
|
|
438
|
-
type: TAG,
|
|
439
|
-
context,
|
|
440
|
-
embedded,
|
|
441
|
-
};
|
|
442
|
-
if (getDefaultTags) {
|
|
443
|
-
query.context = getDefaultTags;
|
|
444
|
-
}
|
|
445
|
-
globalActions?.fetchSchemaForEntity(query);
|
|
446
|
-
}, [globalActions, getDefaultTags, locationType]);
|
|
447
|
-
|
|
448
|
-
// Memoize validation function to avoid recreating on every render
|
|
449
|
-
const validationConfig = useMemo(
|
|
450
|
-
() => ({
|
|
451
|
-
tagsParam: tags,
|
|
452
|
-
injectedTagsParams: injectedTags,
|
|
453
|
-
location,
|
|
454
|
-
tagModule: getDefaultTags,
|
|
455
|
-
eventContextTags,
|
|
456
|
-
}),
|
|
457
|
-
[tags, injectedTags, location, getDefaultTags, eventContextTags],
|
|
458
|
-
);
|
|
459
|
-
|
|
460
|
-
const validateMessageContent = useCallback((value) => {
|
|
461
|
-
if (!value || value.trim() === '') {
|
|
462
|
-
return formatMessage(messages.messageRequired);
|
|
463
|
-
}
|
|
464
|
-
const validationResponse = validateTags({
|
|
465
|
-
content: value,
|
|
466
|
-
...validationConfig,
|
|
467
|
-
}) || {};
|
|
468
|
-
if (validationResponse?.unsupportedTags?.length) {
|
|
469
|
-
return formatMessage(globalMessages.unsupportedTagsValidationError, {
|
|
470
|
-
unsupportedTags: validationResponse.unsupportedTags.join(', '),
|
|
471
|
-
});
|
|
472
|
-
}
|
|
473
|
-
if (validationResponse?.isBraceError) {
|
|
474
|
-
return formatMessage(globalMessages.unbalanacedCurlyBraces);
|
|
475
|
-
}
|
|
476
|
-
return '';
|
|
477
|
-
}, [formatMessage, validationConfig]);
|
|
478
|
-
|
|
479
|
-
useEffect(() => {
|
|
480
|
-
if (!isEditMode) {
|
|
481
|
-
return;
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
if (isEmpty(templateData)) {
|
|
485
|
-
return;
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
const webpushContent = get(templateData, 'versions.base.content.webpush', {});
|
|
489
|
-
|
|
490
|
-
const extractedTemplateName = templateData?.name || '';
|
|
491
|
-
const extractedNotificationTitle = webpushContent?.title || '';
|
|
492
|
-
const extractedMessage = webpushContent?.message || '';
|
|
493
|
-
|
|
494
|
-
// Update state to populate form fields
|
|
495
|
-
setTemplateName(extractedTemplateName);
|
|
496
|
-
setNotificationTitle(extractedNotificationTitle);
|
|
497
|
-
setMessage(extractedMessage);
|
|
498
|
-
|
|
499
|
-
const nextMediaType = webpushContent?.mediaType || WEBPUSH_MEDIA_TYPES.NONE;
|
|
500
|
-
setMediaType(nextMediaType);
|
|
501
|
-
|
|
502
|
-
const existingImage = webpushContent?.image || '';
|
|
503
|
-
if (existingImage) {
|
|
504
|
-
setImageSrc(existingImage);
|
|
505
|
-
setImageUploadMethod(IMAGE_UPLOAD_METHODS.UPLOAD_IMAGE);
|
|
506
|
-
setImageUrl('');
|
|
507
|
-
} else {
|
|
508
|
-
setImageSrc('');
|
|
509
|
-
setImageUrl('');
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
const existingBrandIcon = webpushContent?.brandIcon || '';
|
|
513
|
-
if (existingBrandIcon) {
|
|
514
|
-
setBrandIconOption(BRAND_ICON_OPTIONS.UPLOAD_IMAGE);
|
|
515
|
-
setBrandIconSrc(existingBrandIcon);
|
|
516
|
-
setBrandIconUrl('');
|
|
517
|
-
} else {
|
|
518
|
-
setBrandIconOption(BRAND_ICON_OPTIONS.DONT_SHOW);
|
|
519
|
-
setBrandIconSrc('');
|
|
520
|
-
setBrandIconUrl('');
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
const webpushCtas = Array.isArray(webpushContent?.ctas) ? webpushContent.ctas : [];
|
|
524
|
-
setButtons(
|
|
525
|
-
webpushCtas.map((cta, index) => ({
|
|
526
|
-
text: cta?.actionText || '',
|
|
527
|
-
url: cta?.actionLink || '',
|
|
528
|
-
type: index === 0 ? WEBPUSH_BUTTON_TYPES.PRIMARY : WEBPUSH_BUTTON_TYPES.SECONDARY,
|
|
529
|
-
})),
|
|
530
|
-
);
|
|
531
|
-
|
|
532
|
-
const onClickAction = webpushContent?.onClickAction || {};
|
|
533
|
-
if (onClickAction?.type === ACTION_TYPES.URL) {
|
|
534
|
-
setOnClickBehaviour(ON_CLICK_BEHAVIOUR_OPTIONS.REDIRECT_TO_URL);
|
|
535
|
-
setRedirectUrl(onClickAction?.url || '');
|
|
536
|
-
setRedirectUrlError('');
|
|
537
|
-
} else if (onClickAction?.type === ACTION_TYPES.SITE_URL) {
|
|
538
|
-
setOnClickBehaviour(ON_CLICK_BEHAVIOUR_OPTIONS.SITE_URL);
|
|
539
|
-
setRedirectUrl(websiteLink);
|
|
540
|
-
setRedirectUrlError('');
|
|
541
|
-
} else {
|
|
542
|
-
setOnClickBehaviour(ON_CLICK_BEHAVIOUR_OPTIONS.SITE_URL);
|
|
543
|
-
setRedirectUrl(websiteLink);
|
|
544
|
-
setRedirectUrlError('');
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
updateFieldCompletion('notificationTitle', extractedNotificationTitle.trim().length > 0);
|
|
548
|
-
updateFieldCompletion('message', extractedMessage.trim().length > 0);
|
|
549
|
-
if (isFullMode) {
|
|
550
|
-
updateFieldCompletion('templateName', extractedTemplateName.trim().length > 0);
|
|
551
|
-
setTemplateNameError('');
|
|
552
|
-
}
|
|
553
|
-
setTitleError('');
|
|
554
|
-
setMessageError('');
|
|
555
|
-
|
|
556
|
-
setIsAddingButton(false);
|
|
557
|
-
setButtonBeingAdded(null);
|
|
558
|
-
setEditingButtonIndex(null);
|
|
559
|
-
|
|
560
|
-
updateCharacterCount(
|
|
561
|
-
titleCountRef,
|
|
562
|
-
extractedNotificationTitle.length,
|
|
563
|
-
NOTIFICATION_TITLE_MAX_LENGTH,
|
|
564
|
-
);
|
|
565
|
-
updateCharacterCount(
|
|
566
|
-
messageCountRef,
|
|
567
|
-
extractedMessage.length,
|
|
568
|
-
MESSAGE_MAX_LENGTH,
|
|
569
|
-
);
|
|
570
|
-
}, [
|
|
571
|
-
isEditMode,
|
|
572
|
-
templateData,
|
|
573
|
-
isFullMode,
|
|
574
|
-
updateFieldCompletion,
|
|
575
|
-
updateCharacterCount,
|
|
576
|
-
]);
|
|
577
|
-
|
|
578
|
-
const handleTemplateNameChange = useCallback((e) => {
|
|
579
|
-
const { value } = e.target;
|
|
580
|
-
setTemplateName(value);
|
|
581
|
-
if (isFullMode) {
|
|
582
|
-
const nextError = validateTemplateName(value);
|
|
583
|
-
setTemplateNameError((prev) => (prev === nextError ? prev : nextError));
|
|
584
|
-
}
|
|
585
|
-
updateFieldCompletion('templateName', value.trim().length > 0);
|
|
586
|
-
}, [isFullMode, updateFieldCompletion, validateTemplateName]);
|
|
587
|
-
|
|
588
|
-
const handleNotificationTitleChange = useCallback((e) => {
|
|
589
|
-
const { value } = e.target;
|
|
590
|
-
setNotificationTitle(value);
|
|
591
|
-
const nextError = validateTitle(value);
|
|
592
|
-
setTitleError((prev) => (prev === nextError ? prev : nextError));
|
|
593
|
-
updateFieldCompletion('notificationTitle', value.trim().length > 0);
|
|
594
|
-
updateCharacterCount(titleCountRef, value.length, NOTIFICATION_TITLE_MAX_LENGTH);
|
|
595
|
-
}, [updateCharacterCount, updateFieldCompletion, validateTitle]);
|
|
596
|
-
|
|
597
|
-
// Optimize message change handler - use functional updates where possible
|
|
598
|
-
const handleMessageChange = useCallback((e) => {
|
|
599
|
-
const { value } = e.target;
|
|
600
|
-
// Cap length to maximum (maxLength not passed to TextArea to avoid embedded character count)
|
|
601
|
-
const cappedValue = value.length > MESSAGE_MAX_LENGTH
|
|
602
|
-
? value.slice(0, MESSAGE_MAX_LENGTH)
|
|
603
|
-
: value;
|
|
604
|
-
if (cappedValue !== value) {
|
|
605
|
-
e.target.value = cappedValue;
|
|
606
|
-
}
|
|
607
|
-
setMessage(cappedValue);
|
|
608
|
-
const nextError = validateMessageContent(cappedValue);
|
|
609
|
-
setMessageError((prev) => (prev === nextError ? prev : nextError));
|
|
610
|
-
updateFieldCompletion('message', cappedValue.trim().length > 0);
|
|
611
|
-
updateCharacterCount(messageCountRef, cappedValue.length, MESSAGE_MAX_LENGTH);
|
|
612
|
-
}, [updateCharacterCount, updateFieldCompletion, validateMessageContent]);
|
|
613
|
-
|
|
614
|
-
const handleMediaTypeChange = useCallback((value) => {
|
|
615
|
-
setMediaType(value);
|
|
616
|
-
if (value === WEBPUSH_MEDIA_TYPES.NONE) {
|
|
617
|
-
setImageSrc('');
|
|
618
|
-
setImageUrl('');
|
|
619
|
-
setImageUploadMethod(IMAGE_UPLOAD_METHODS.UPLOAD_IMAGE);
|
|
620
|
-
}
|
|
621
|
-
}, []);
|
|
622
|
-
|
|
623
|
-
const handleImageUploadMethodChange = useCallback((e) => {
|
|
624
|
-
const method = e.target.value;
|
|
625
|
-
setImageUploadMethod(method);
|
|
626
|
-
setImageSrc('');
|
|
627
|
-
setImageUrl('');
|
|
628
|
-
}, []);
|
|
629
|
-
|
|
630
|
-
// Image upload handlers
|
|
631
|
-
const setUpdateWebPushImageSrc = useCallback(
|
|
632
|
-
(filePath) => {
|
|
633
|
-
setImageSrc(filePath);
|
|
634
|
-
webPushActions.clearWebPushAsset(0);
|
|
635
|
-
},
|
|
636
|
-
[webPushActions],
|
|
637
|
-
);
|
|
638
|
-
|
|
639
|
-
const updateOnWebPushImageReUpload = useCallback(() => {
|
|
640
|
-
setImageSrc('');
|
|
641
|
-
}, []);
|
|
642
|
-
|
|
643
|
-
const uploadWebPushAsset = (file, type, fileParams) => {
|
|
644
|
-
setActiveUploadField(UPLOAD_FIELD_TYPES.IMAGE);
|
|
645
|
-
webPushActions.uploadWebPushAsset(file, type, fileParams, 0);
|
|
646
|
-
};
|
|
647
|
-
|
|
648
|
-
const handleImageUrlChange = useCallback((url) => {
|
|
649
|
-
setImageUrl(url);
|
|
650
|
-
// Clear imageSrc when URL changes
|
|
651
|
-
if (url !== imageUrl) {
|
|
652
|
-
setImageSrc('');
|
|
653
|
-
}
|
|
654
|
-
}, [imageUrl]);
|
|
655
|
-
|
|
656
|
-
const handleImageValidationStateChange = useCallback((isValidating) => {
|
|
657
|
-
setIsImageValidating(isValidating);
|
|
658
|
-
}, []);
|
|
659
|
-
|
|
660
|
-
const handleImageUploadStateChange = useCallback((isUploading) => {
|
|
661
|
-
setIsImageUploading(isUploading);
|
|
662
|
-
}, []);
|
|
663
|
-
|
|
664
|
-
// Restore image from uploaded asset data
|
|
665
|
-
useEffect(() => {
|
|
666
|
-
const imageDataObj = get(webPush, 'uploadedAssetData0') || get(webPush, 'uploadedAssetData');
|
|
667
|
-
if (!isEmpty(imageDataObj)) {
|
|
668
|
-
const { secure_file_path = '' } = get(imageDataObj, 'metaInfo', {});
|
|
669
|
-
if (secure_file_path) {
|
|
670
|
-
setUpdateWebPushImageSrc(secure_file_path);
|
|
671
|
-
}
|
|
672
|
-
}
|
|
673
|
-
}, [webPush, setUpdateWebPushImageSrc]);
|
|
674
|
-
|
|
675
|
-
// Brand icon handlers
|
|
676
|
-
const handleBrandIconChange = useCallback((e) => {
|
|
677
|
-
const option = e.target.value;
|
|
678
|
-
setBrandIconOption(option);
|
|
679
|
-
setBrandIconSrc('');
|
|
680
|
-
setBrandIconUrl('');
|
|
681
|
-
}, []);
|
|
682
|
-
|
|
683
|
-
const setUpdateWebPushBrandIconSrc = useCallback(
|
|
684
|
-
(filePath) => {
|
|
685
|
-
setBrandIconSrc(filePath);
|
|
686
|
-
webPushActions.clearWebPushAsset(1);
|
|
687
|
-
},
|
|
688
|
-
[webPushActions],
|
|
689
|
-
);
|
|
690
|
-
|
|
691
|
-
const updateOnWebPushBrandIconReUpload = useCallback(() => {
|
|
692
|
-
setBrandIconSrc('');
|
|
693
|
-
}, []);
|
|
694
|
-
|
|
695
|
-
const uploadWebPushBrandIconAsset = (file, type, fileParams) => {
|
|
696
|
-
setActiveUploadField(UPLOAD_FIELD_TYPES.BRAND_ICON);
|
|
697
|
-
webPushActions.uploadWebPushAsset(file, type, fileParams, 1);
|
|
698
|
-
};
|
|
699
|
-
|
|
700
|
-
const handleBrandIconUrlChange = useCallback((url) => {
|
|
701
|
-
setBrandIconUrl(url);
|
|
702
|
-
// Clear brandIconSrc when URL changes
|
|
703
|
-
if (url !== brandIconUrl) {
|
|
704
|
-
setBrandIconSrc('');
|
|
705
|
-
}
|
|
706
|
-
}, [brandIconUrl]);
|
|
707
|
-
|
|
708
|
-
const handleBrandIconValidationStateChange = useCallback((isValidating) => {
|
|
709
|
-
setIsBrandIconValidating(isValidating);
|
|
710
|
-
}, []);
|
|
711
|
-
|
|
712
|
-
const handleBrandIconUploadStateChange = useCallback((isUploading) => {
|
|
713
|
-
setIsBrandIconUploading(isUploading);
|
|
714
|
-
}, []);
|
|
715
|
-
|
|
716
|
-
// Restore brand icon from uploaded asset data
|
|
717
|
-
useEffect(() => {
|
|
718
|
-
const brandIconDataObj = get(webPush, 'uploadedAssetData1');
|
|
719
|
-
if (!isEmpty(brandIconDataObj)) {
|
|
720
|
-
const { secure_file_path = '' } = get(brandIconDataObj, 'metaInfo', {});
|
|
721
|
-
if (secure_file_path) {
|
|
722
|
-
setUpdateWebPushBrandIconSrc(secure_file_path);
|
|
723
|
-
}
|
|
724
|
-
}
|
|
725
|
-
}, [webPush, setUpdateWebPushBrandIconSrc]);
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
// Render character count for notification title
|
|
729
|
-
const renderTitleCharacterCount = (className = "webpush-character-count") => {
|
|
730
|
-
if (!SHOW_CHARACTER_COUNT) return null;
|
|
731
|
-
|
|
732
|
-
const maxLength = NOTIFICATION_TITLE_MAX_LENGTH;
|
|
733
|
-
|
|
734
|
-
return (
|
|
735
|
-
<CapLabel type="label2" className={className}>
|
|
736
|
-
<span ref={titleCountRef}>
|
|
737
|
-
{formatMessage(messages.characterCount, {
|
|
738
|
-
currentLength: notificationTitle.length,
|
|
739
|
-
maxLength,
|
|
740
|
-
})}
|
|
741
|
-
</span>
|
|
742
|
-
</CapLabel>
|
|
743
|
-
);
|
|
744
|
-
};
|
|
745
|
-
|
|
746
|
-
// Render character count for message
|
|
747
|
-
const renderMessageCharacterCount = (className = "webpush-character-count") => {
|
|
748
|
-
if (!SHOW_CHARACTER_COUNT) return null;
|
|
749
|
-
|
|
750
|
-
const maxLength = MESSAGE_MAX_LENGTH;
|
|
751
|
-
|
|
752
|
-
return (
|
|
753
|
-
<CapLabel type="label2" className={className}>
|
|
754
|
-
<span ref={messageCountRef}>
|
|
755
|
-
{formatMessage(messages.characterCount, {
|
|
756
|
-
currentLength: message.length,
|
|
757
|
-
maxLength,
|
|
758
|
-
})}
|
|
759
|
-
</span>
|
|
760
|
-
</CapLabel>
|
|
761
|
-
);
|
|
762
|
-
};
|
|
763
|
-
|
|
764
|
-
const handleOnClickBehaviourChange = useCallback((e) => {
|
|
765
|
-
const value = e.target.value;
|
|
766
|
-
setOnClickBehaviour(value);
|
|
767
|
-
if (value !== ON_CLICK_BEHAVIOUR_OPTIONS.REDIRECT_TO_URL) {
|
|
768
|
-
setRedirectUrl('');
|
|
769
|
-
setRedirectUrlError('');
|
|
770
|
-
}
|
|
771
|
-
}, []);
|
|
772
|
-
|
|
773
|
-
const handleRedirectUrlChange = useCallback((e) => {
|
|
774
|
-
const { value } = e.target;
|
|
775
|
-
setRedirectUrl(value);
|
|
776
|
-
const nextError = validateUrl(value);
|
|
777
|
-
setRedirectUrlError((prev) => (prev === nextError ? prev : nextError));
|
|
778
|
-
}, [validateUrl]);
|
|
779
|
-
|
|
780
|
-
// Optimized tag insertion handlers - split into separate callbacks
|
|
781
|
-
const handleTagSelectTitle = useCallback((tagValue) => {
|
|
782
|
-
const tagText = `{{${tagValue}}}`;
|
|
783
|
-
setNotificationTitle((prevTitle) => {
|
|
784
|
-
const nextTitle = `${prevTitle}${tagText}`.slice(0, NOTIFICATION_TITLE_MAX_LENGTH);
|
|
785
|
-
// Use functional updates to avoid dependency on notificationTitle
|
|
786
|
-
const nextError = validateTitle(nextTitle);
|
|
787
|
-
setTitleError((prev) => (prev === nextError ? prev : nextError));
|
|
788
|
-
updateFieldCompletion('notificationTitle', nextTitle.trim().length > 0);
|
|
789
|
-
updateCharacterCount(titleCountRef, nextTitle.length, NOTIFICATION_TITLE_MAX_LENGTH);
|
|
790
|
-
return nextTitle;
|
|
791
|
-
});
|
|
792
|
-
}, [updateCharacterCount, updateFieldCompletion, validateTitle]);
|
|
793
|
-
|
|
794
|
-
const handleTagSelectMessage = useCallback((tagValue) => {
|
|
795
|
-
const tagText = `{{${tagValue}}}`;
|
|
796
|
-
setMessage((prevMessage) => {
|
|
797
|
-
const nextMessage = `${prevMessage}${tagText}`.slice(0, MESSAGE_MAX_LENGTH);
|
|
798
|
-
// Use functional updates to avoid dependency on message
|
|
799
|
-
const nextError = validateMessageContent(nextMessage);
|
|
800
|
-
setMessageError((prev) => (prev === nextError ? prev : nextError));
|
|
801
|
-
updateFieldCompletion('message', nextMessage.trim().length > 0);
|
|
802
|
-
updateCharacterCount(messageCountRef, nextMessage.length, MESSAGE_MAX_LENGTH);
|
|
803
|
-
return nextMessage;
|
|
804
|
-
});
|
|
805
|
-
}, [updateCharacterCount, updateFieldCompletion, validateMessageContent]);
|
|
806
|
-
|
|
807
|
-
// Button handlers
|
|
808
|
-
const handleAddPrimaryButton = useCallback(() => {
|
|
809
|
-
setIsAddingButton(true);
|
|
810
|
-
setButtonBeingAdded(WEBPUSH_BUTTON_TYPES.PRIMARY);
|
|
811
|
-
setEditingButtonIndex(null);
|
|
812
|
-
}, []);
|
|
813
|
-
|
|
814
|
-
const handleAddSecondaryButton = useCallback(() => {
|
|
815
|
-
setIsAddingButton(true);
|
|
816
|
-
setButtonBeingAdded(WEBPUSH_BUTTON_TYPES.SECONDARY);
|
|
817
|
-
setEditingButtonIndex(null);
|
|
818
|
-
}, []);
|
|
819
|
-
|
|
820
|
-
const handleButtonSave = useCallback((buttonData) => {
|
|
821
|
-
if (editingButtonIndex !== null) {
|
|
822
|
-
// Editing existing button
|
|
823
|
-
const newButtons = [...buttons];
|
|
824
|
-
newButtons[editingButtonIndex] = buttonData;
|
|
825
|
-
setButtons(newButtons);
|
|
826
|
-
} else {
|
|
827
|
-
// Adding new button
|
|
828
|
-
setButtons((prev) => [...prev, buttonData]);
|
|
829
|
-
}
|
|
830
|
-
setIsAddingButton(false);
|
|
831
|
-
setButtonBeingAdded(null);
|
|
832
|
-
setEditingButtonIndex(null);
|
|
833
|
-
}, [buttons, editingButtonIndex]);
|
|
834
|
-
|
|
835
|
-
const handleButtonCancel = useCallback(() => {
|
|
836
|
-
setIsAddingButton(false);
|
|
837
|
-
setButtonBeingAdded(null);
|
|
838
|
-
setEditingButtonIndex(null);
|
|
839
|
-
}, []);
|
|
840
|
-
|
|
841
|
-
const handleButtonEdit = useCallback((index) => {
|
|
842
|
-
setIsAddingButton(true);
|
|
843
|
-
setButtonBeingAdded(buttons[index].type);
|
|
844
|
-
setEditingButtonIndex(index);
|
|
845
|
-
}, [buttons]);
|
|
846
|
-
|
|
847
|
-
const handleButtonDelete = useCallback((index) => {
|
|
848
|
-
const newButtons = [...buttons];
|
|
849
|
-
newButtons.splice(index, 1);
|
|
850
|
-
setButtons(newButtons);
|
|
851
|
-
}, [buttons]);
|
|
852
|
-
|
|
853
|
-
const handleButtonReorder = useCallback((fromIndex, toIndex) => {
|
|
854
|
-
const newButtons = [...buttons];
|
|
855
|
-
const [movedButton] = newButtons.splice(fromIndex, 1);
|
|
856
|
-
newButtons.splice(toIndex, 0, movedButton);
|
|
857
|
-
setButtons(newButtons);
|
|
858
|
-
}, [buttons]);
|
|
859
|
-
|
|
860
|
-
const isAddFlow = useMemo(
|
|
861
|
-
() => isAddingButton && editingButtonIndex === null,
|
|
862
|
-
[isAddingButton, editingButtonIndex],
|
|
863
|
-
);
|
|
864
|
-
const isEditFlow = useMemo(
|
|
865
|
-
() => isAddingButton && editingButtonIndex !== null,
|
|
866
|
-
[isAddingButton, editingButtonIndex],
|
|
867
|
-
);
|
|
868
|
-
|
|
869
|
-
const showAddPrimaryButton = useMemo(
|
|
870
|
-
() => buttons.length === 0 && !isAddingButton,
|
|
871
|
-
[buttons.length, isAddingButton],
|
|
872
|
-
);
|
|
873
|
-
const showAddSecondaryButton = useMemo(
|
|
874
|
-
() => buttons.length === 1 && !isAddingButton,
|
|
875
|
-
[buttons.length, isAddingButton],
|
|
876
|
-
);
|
|
877
|
-
const showDisabledSecondaryDuringPrimary = useMemo(
|
|
878
|
-
() => isAddFlow && buttonBeingAdded === WEBPUSH_BUTTON_TYPES.PRIMARY && buttons.length === 0,
|
|
879
|
-
[isAddFlow, buttonBeingAdded, buttons.length],
|
|
880
|
-
);
|
|
881
|
-
const disableSecondaryAddButton = useMemo(
|
|
882
|
-
() => isAddFlow && buttonBeingAdded === WEBPUSH_BUTTON_TYPES.PRIMARY,
|
|
883
|
-
[isAddFlow, buttonBeingAdded],
|
|
884
|
-
);
|
|
885
|
-
|
|
886
|
-
const renderButtonForm = (isEditMode) => (
|
|
887
|
-
<ButtonForm
|
|
888
|
-
buttonType={buttonBeingAdded}
|
|
889
|
-
formatMessage={formatMessage}
|
|
890
|
-
onSave={handleButtonSave}
|
|
891
|
-
onCancel={handleButtonCancel}
|
|
892
|
-
initialData={isEditMode && editingButtonIndex !== null ? buttons[editingButtonIndex] : null}
|
|
893
|
-
isEditMode={isEditMode}
|
|
894
|
-
/>
|
|
895
|
-
);
|
|
896
|
-
|
|
897
|
-
useEffect(() => {
|
|
898
|
-
updateCharacterCount(
|
|
899
|
-
titleCountRef,
|
|
900
|
-
notificationTitle.length,
|
|
901
|
-
NOTIFICATION_TITLE_MAX_LENGTH,
|
|
902
|
-
);
|
|
903
|
-
updateCharacterCount(
|
|
904
|
-
messageCountRef,
|
|
905
|
-
message.length,
|
|
906
|
-
MESSAGE_MAX_LENGTH,
|
|
907
|
-
);
|
|
908
|
-
}, [updateCharacterCount, notificationTitle, message]);
|
|
909
|
-
|
|
910
|
-
useEffect(() => {
|
|
911
|
-
setFieldCompletion((prev) => {
|
|
912
|
-
const nextTemplateNameComplete = !isFullMode
|
|
913
|
-
|| templateName.trim().length > 0;
|
|
914
|
-
if (prev.templateName === nextTemplateNameComplete) {
|
|
915
|
-
return prev;
|
|
916
|
-
}
|
|
917
|
-
return {
|
|
918
|
-
...prev,
|
|
919
|
-
templateName: nextTemplateNameComplete,
|
|
920
|
-
};
|
|
921
|
-
});
|
|
922
|
-
}, [isFullMode, templateName]);
|
|
923
|
-
|
|
924
|
-
const isFormValid = () => {
|
|
925
|
-
const templateNameInvalid = isFullMode && validateTemplateName(templateName);
|
|
926
|
-
const titleValidation = validateTitle(notificationTitle);
|
|
927
|
-
const messageValidation = validateMessageContent(message);
|
|
928
|
-
|
|
929
|
-
setTemplateNameError((prev) => (prev === templateNameInvalid ? prev : templateNameInvalid));
|
|
930
|
-
setTitleError((prev) => (prev === titleValidation ? prev : titleValidation));
|
|
931
|
-
setMessageError((prev) => (prev === messageValidation ? prev : messageValidation));
|
|
932
|
-
|
|
933
|
-
return !(templateNameInvalid || titleValidation || messageValidation);
|
|
934
|
-
};
|
|
935
|
-
|
|
936
|
-
const handleSave = () => {
|
|
937
|
-
if (!isFormValid()) {
|
|
938
|
-
return;
|
|
939
|
-
}
|
|
940
|
-
|
|
941
|
-
// Set flag to indicate save/edit operation has been initiated
|
|
942
|
-
saveInitiatedRef.current = true;
|
|
943
|
-
|
|
944
|
-
const payload = createWebPushPayload({
|
|
945
|
-
templateName,
|
|
946
|
-
notificationTitle,
|
|
947
|
-
message,
|
|
948
|
-
mediaType,
|
|
949
|
-
accountId,
|
|
950
|
-
isFullMode,
|
|
951
|
-
imageSrc,
|
|
952
|
-
imageUrl,
|
|
953
|
-
imageUploadMethod,
|
|
954
|
-
brandIconOption,
|
|
955
|
-
brandIconSrc,
|
|
956
|
-
brandIconUrl,
|
|
957
|
-
buttons,
|
|
958
|
-
onClickBehaviour,
|
|
959
|
-
redirectUrl,
|
|
960
|
-
websiteLink,
|
|
961
|
-
});
|
|
962
|
-
|
|
963
|
-
// In library mode (not full mode), use getFormData to communicate with parent
|
|
964
|
-
if (!isFullMode && getFormData) {
|
|
965
|
-
const formDataForLibrary = {
|
|
966
|
-
validity: true,
|
|
967
|
-
value: payload,
|
|
968
|
-
type: 'WEBPUSH',
|
|
969
|
-
};
|
|
970
|
-
getFormData(formDataForLibrary);
|
|
971
|
-
if (handleClose) {
|
|
972
|
-
handleClose();
|
|
973
|
-
}
|
|
974
|
-
return;
|
|
975
|
-
}
|
|
976
|
-
|
|
977
|
-
// Full mode: proceed with API calls
|
|
978
|
-
if (isEditMode) {
|
|
979
|
-
// Get template ID from params or templateData
|
|
980
|
-
const templateId = params?.id || templateData?._id;
|
|
981
|
-
if (templateId) {
|
|
982
|
-
webPushActions.editTemplate(
|
|
983
|
-
{
|
|
984
|
-
...payload,
|
|
985
|
-
_id: templateId,
|
|
986
|
-
},
|
|
987
|
-
(resp, errorMessage) => {
|
|
988
|
-
if (!errorMessage) {
|
|
989
|
-
if (onCreateComplete) {
|
|
990
|
-
onCreateComplete(true);
|
|
991
|
-
}
|
|
992
|
-
if (handleClose) {
|
|
993
|
-
handleClose();
|
|
994
|
-
}
|
|
995
|
-
}
|
|
996
|
-
},
|
|
997
|
-
);
|
|
998
|
-
}
|
|
999
|
-
} else {
|
|
1000
|
-
webPushActions.createTemplate(payload);
|
|
1001
|
-
}
|
|
1002
|
-
};
|
|
1003
|
-
|
|
1004
|
-
// Clear response state on mount to prevent stale responses from triggering callbacks
|
|
1005
|
-
useEffect(() => {
|
|
1006
|
-
webPushActions.clearCreateResponse();
|
|
1007
|
-
webPushActions.clearEditResponse();
|
|
1008
|
-
saveInitiatedRef.current = false;
|
|
1009
|
-
}, []);
|
|
1010
|
-
|
|
1011
|
-
// Handle create response
|
|
1012
|
-
useEffect(() => {
|
|
1013
|
-
const response = webPush?.response || {};
|
|
1014
|
-
if (
|
|
1015
|
-
response &&
|
|
1016
|
-
Object.keys(response).length > 0 &&
|
|
1017
|
-
!isEditMode &&
|
|
1018
|
-
saveInitiatedRef.current
|
|
1019
|
-
) {
|
|
1020
|
-
// Reset flag after handling response
|
|
1021
|
-
saveInitiatedRef.current = false;
|
|
1022
|
-
if (onCreateComplete) {
|
|
1023
|
-
onCreateComplete(true);
|
|
1024
|
-
}
|
|
1025
|
-
if (handleClose) {
|
|
1026
|
-
handleClose();
|
|
1027
|
-
}
|
|
1028
|
-
}
|
|
1029
|
-
}, [webPush?.response, onCreateComplete, handleClose, isEditMode]);
|
|
1030
|
-
|
|
1031
|
-
// Handle edit response
|
|
1032
|
-
useEffect(() => {
|
|
1033
|
-
const editResponse = webPush?.editResponse || {};
|
|
1034
|
-
if (
|
|
1035
|
-
editResponse &&
|
|
1036
|
-
Object.keys(editResponse).length > 0 &&
|
|
1037
|
-
isEditMode &&
|
|
1038
|
-
saveInitiatedRef.current
|
|
1039
|
-
) {
|
|
1040
|
-
// Reset flag after handling response
|
|
1041
|
-
saveInitiatedRef.current = false;
|
|
1042
|
-
if (onCreateComplete) {
|
|
1043
|
-
onCreateComplete(true);
|
|
1044
|
-
}
|
|
1045
|
-
if (handleClose) {
|
|
1046
|
-
handleClose();
|
|
1047
|
-
}
|
|
1048
|
-
}
|
|
1049
|
-
}, [webPush?.editResponse, onCreateComplete, handleClose, isEditMode]);
|
|
1050
|
-
|
|
1051
|
-
// Handle getFormData request from parent (library mode)
|
|
1052
|
-
useEffect(() => {
|
|
1053
|
-
if (isGetFormData && getFormData && isFormValid()) {
|
|
1054
|
-
const payload = createWebPushPayload({
|
|
1055
|
-
templateName,
|
|
1056
|
-
notificationTitle,
|
|
1057
|
-
message,
|
|
1058
|
-
mediaType,
|
|
1059
|
-
accountId,
|
|
1060
|
-
isFullMode,
|
|
1061
|
-
imageSrc,
|
|
1062
|
-
imageUrl,
|
|
1063
|
-
imageUploadMethod,
|
|
1064
|
-
brandIconOption,
|
|
1065
|
-
brandIconSrc,
|
|
1066
|
-
brandIconUrl,
|
|
1067
|
-
buttons,
|
|
1068
|
-
onClickBehaviour,
|
|
1069
|
-
redirectUrl,
|
|
1070
|
-
});
|
|
1071
|
-
const formDataForLibrary = {
|
|
1072
|
-
validity: true,
|
|
1073
|
-
value: payload,
|
|
1074
|
-
type: 'WEBPUSH',
|
|
1075
|
-
};
|
|
1076
|
-
getFormData(formDataForLibrary);
|
|
1077
|
-
}
|
|
1078
|
-
}, [isGetFormData, getFormData, templateName, notificationTitle, message, mediaType, accountId, isFullMode, imageSrc, imageUrl, imageUploadMethod, brandIconOption, brandIconSrc, brandIconUrl, buttons, onClickBehaviour, redirectUrl]);
|
|
1079
|
-
|
|
1080
|
-
const isUploadingAsset = useMemo(
|
|
1081
|
-
() => webPush?.assetUploading || false,
|
|
1082
|
-
[webPush?.assetUploading],
|
|
1083
|
-
);
|
|
1084
|
-
|
|
1085
|
-
// Track which field is currently controlling uploads/validation
|
|
1086
|
-
useEffect(() => {
|
|
1087
|
-
if (isImageValidating || isImageUploading) {
|
|
1088
|
-
setActiveUploadField(UPLOAD_FIELD_TYPES.IMAGE);
|
|
1089
|
-
return;
|
|
1090
|
-
}
|
|
1091
|
-
if (isBrandIconValidating || isBrandIconUploading) {
|
|
1092
|
-
setActiveUploadField(UPLOAD_FIELD_TYPES.BRAND_ICON);
|
|
1093
|
-
return;
|
|
1094
|
-
}
|
|
1095
|
-
if (!isUploadingAsset) {
|
|
1096
|
-
setActiveUploadField(null);
|
|
1097
|
-
}
|
|
1098
|
-
}, [
|
|
1099
|
-
isImageValidating,
|
|
1100
|
-
isImageUploading,
|
|
1101
|
-
isBrandIconValidating,
|
|
1102
|
-
isBrandIconUploading,
|
|
1103
|
-
isUploadingAsset,
|
|
1104
|
-
]);
|
|
1105
|
-
|
|
1106
|
-
const isImageFieldActive = useMemo(
|
|
1107
|
-
() => (
|
|
1108
|
-
isImageValidating
|
|
1109
|
-
|| isImageUploading
|
|
1110
|
-
|| (isUploadingAsset && activeUploadField === UPLOAD_FIELD_TYPES.IMAGE)
|
|
1111
|
-
),
|
|
1112
|
-
[
|
|
1113
|
-
isImageValidating,
|
|
1114
|
-
isImageUploading,
|
|
1115
|
-
isUploadingAsset,
|
|
1116
|
-
activeUploadField,
|
|
1117
|
-
],
|
|
1118
|
-
);
|
|
1119
|
-
|
|
1120
|
-
const isBrandIconFieldActive = useMemo(
|
|
1121
|
-
() => (
|
|
1122
|
-
isBrandIconValidating
|
|
1123
|
-
|| isBrandIconUploading
|
|
1124
|
-
|| (isUploadingAsset && activeUploadField === UPLOAD_FIELD_TYPES.BRAND_ICON)
|
|
1125
|
-
),
|
|
1126
|
-
[
|
|
1127
|
-
isBrandIconValidating,
|
|
1128
|
-
isBrandIconUploading,
|
|
1129
|
-
isUploadingAsset,
|
|
1130
|
-
activeUploadField,
|
|
1131
|
-
],
|
|
1132
|
-
);
|
|
1133
|
-
|
|
1134
|
-
const isAnyUploadActive = useMemo(
|
|
1135
|
-
() => isImageFieldActive || isBrandIconFieldActive,
|
|
1136
|
-
[isImageFieldActive, isBrandIconFieldActive],
|
|
1137
|
-
);
|
|
1138
|
-
|
|
1139
|
-
const isMediaSectionLocked = useMemo(
|
|
1140
|
-
() => isBrandIconFieldActive,
|
|
1141
|
-
[isBrandIconFieldActive],
|
|
1142
|
-
);
|
|
1143
|
-
|
|
1144
|
-
const isBrandIconSectionLocked = useMemo(
|
|
1145
|
-
() => isImageFieldActive,
|
|
1146
|
-
[isImageFieldActive],
|
|
1147
|
-
);
|
|
1148
|
-
|
|
1149
|
-
// Optimize tagListCommonProps - split into stable and dynamic parts
|
|
1150
|
-
const moduleFilterEnabled = useMemo(
|
|
1151
|
-
() => location?.query?.type !== 'embedded',
|
|
1152
|
-
[location?.query?.type],
|
|
1153
|
-
);
|
|
1154
|
-
|
|
1155
|
-
const tagListLabel = useMemo(
|
|
1156
|
-
() => formatMessage(messages.addLabels),
|
|
1157
|
-
[formatMessage],
|
|
1158
|
-
);
|
|
1159
|
-
|
|
1160
|
-
// Stable props that don't change often
|
|
1161
|
-
const tagListStableProps = useMemo(
|
|
1162
|
-
() => ({
|
|
1163
|
-
moduleFilterEnabled,
|
|
1164
|
-
label: tagListLabel,
|
|
1165
|
-
onContextChange: handleOnTagsContextChange,
|
|
1166
|
-
location,
|
|
1167
|
-
}),
|
|
1168
|
-
[moduleFilterEnabled, tagListLabel, handleOnTagsContextChange, location],
|
|
1169
|
-
);
|
|
1170
|
-
|
|
1171
|
-
// Dynamic props that change with tags
|
|
1172
|
-
const tagListDynamicProps = useMemo(
|
|
1173
|
-
() => ({
|
|
1174
|
-
tags,
|
|
1175
|
-
injectedTags,
|
|
1176
|
-
selectedOfferDetails,
|
|
1177
|
-
eventContextTags,
|
|
1178
|
-
forwardedTags,
|
|
1179
|
-
}),
|
|
1180
|
-
[tags, injectedTags, selectedOfferDetails, eventContextTags, forwardedTags],
|
|
1181
|
-
);
|
|
1182
|
-
|
|
1183
|
-
// Memoized TagList components with optimized props
|
|
1184
|
-
const titleTagList = useMemo(
|
|
1185
|
-
() => (
|
|
1186
|
-
<MemoizedTagList
|
|
1187
|
-
{...tagListStableProps}
|
|
1188
|
-
{...tagListDynamicProps}
|
|
1189
|
-
onTagSelect={handleTagSelectTitle}
|
|
1190
|
-
/>
|
|
1191
|
-
),
|
|
1192
|
-
[tagListStableProps, tagListDynamicProps, handleTagSelectTitle],
|
|
1193
|
-
);
|
|
1194
|
-
|
|
1195
|
-
const messageTagList = useMemo(
|
|
1196
|
-
() => (
|
|
1197
|
-
<MemoizedTagList
|
|
1198
|
-
{...tagListStableProps}
|
|
1199
|
-
{...tagListDynamicProps}
|
|
1200
|
-
onTagSelect={handleTagSelectMessage}
|
|
1201
|
-
/>
|
|
1202
|
-
),
|
|
1203
|
-
[tagListStableProps, tagListDynamicProps, handleTagSelectMessage],
|
|
1204
|
-
);
|
|
1205
|
-
|
|
1206
|
-
const isSaveDisabled = useMemo(
|
|
1207
|
-
() => (
|
|
1208
|
-
createTemplateInProgress
|
|
1209
|
-
|| editTemplateInProgress
|
|
1210
|
-
|| isUploadingAsset
|
|
1211
|
-
|| isImageValidating
|
|
1212
|
-
|| isImageUploading
|
|
1213
|
-
|| isBrandIconValidating
|
|
1214
|
-
|| isBrandIconUploading
|
|
1215
|
-
|| isAddingButton
|
|
1216
|
-
|| (isFullMode && !fieldCompletion.templateName)
|
|
1217
|
-
|| !fieldCompletion.notificationTitle
|
|
1218
|
-
|| !fieldCompletion.message
|
|
1219
|
-
|| !accountId
|
|
1220
|
-
|| (
|
|
1221
|
-
mediaType === WEBPUSH_MEDIA_TYPES.IMAGE
|
|
1222
|
-
&& (
|
|
1223
|
-
(imageUploadMethod === IMAGE_UPLOAD_METHODS.UPLOAD_IMAGE && !imageSrc)
|
|
1224
|
-
|| (imageUploadMethod === IMAGE_UPLOAD_METHODS.ADD_IMAGE_URL && !imageSrc)
|
|
1225
|
-
)
|
|
1226
|
-
)
|
|
1227
|
-
|| (
|
|
1228
|
-
brandIconOption !== BRAND_ICON_OPTIONS.DONT_SHOW
|
|
1229
|
-
&& (
|
|
1230
|
-
(brandIconOption === BRAND_ICON_OPTIONS.UPLOAD_IMAGE && !brandIconSrc)
|
|
1231
|
-
|| (brandIconOption === BRAND_ICON_OPTIONS.ADD_IMAGE_URL && !brandIconSrc)
|
|
1232
|
-
)
|
|
1233
|
-
)
|
|
1234
|
-
|| (onClickBehaviour === ON_CLICK_BEHAVIOUR_OPTIONS.REDIRECT_TO_URL && (!redirectUrl.trim() || redirectUrlError))
|
|
1235
|
-
),
|
|
1236
|
-
[
|
|
1237
|
-
createTemplateInProgress,
|
|
1238
|
-
editTemplateInProgress,
|
|
1239
|
-
isUploadingAsset,
|
|
1240
|
-
isImageValidating,
|
|
1241
|
-
isImageUploading,
|
|
1242
|
-
isBrandIconValidating,
|
|
1243
|
-
isBrandIconUploading,
|
|
1244
|
-
isAddingButton,
|
|
1245
|
-
isFullMode,
|
|
1246
|
-
fieldCompletion.templateName,
|
|
1247
|
-
fieldCompletion.notificationTitle,
|
|
1248
|
-
fieldCompletion.message,
|
|
1249
|
-
accountId,
|
|
1250
|
-
mediaType,
|
|
1251
|
-
imageUploadMethod,
|
|
1252
|
-
imageSrc,
|
|
1253
|
-
brandIconOption,
|
|
1254
|
-
brandIconSrc,
|
|
1255
|
-
onClickBehaviour,
|
|
1256
|
-
redirectUrl,
|
|
1257
|
-
redirectUrlError,
|
|
1258
|
-
],
|
|
1259
|
-
);
|
|
1260
|
-
|
|
1261
|
-
const errorText = useMemo(() => {
|
|
1262
|
-
const error = isEditMode ? editTemplateError : createTemplateError;
|
|
1263
|
-
if (!error) {
|
|
1264
|
-
return '';
|
|
1265
|
-
}
|
|
1266
|
-
if (typeof error === 'string') {
|
|
1267
|
-
return error;
|
|
1268
|
-
}
|
|
1269
|
-
if (error?.message) {
|
|
1270
|
-
return error.message;
|
|
1271
|
-
}
|
|
1272
|
-
if (typeof error?.toJS === 'function') {
|
|
1273
|
-
const errorObject = error.toJS();
|
|
1274
|
-
if (typeof errorObject === 'string') {
|
|
1275
|
-
return errorObject;
|
|
1276
|
-
}
|
|
1277
|
-
if (errorObject?.message) {
|
|
1278
|
-
return errorObject.message;
|
|
1279
|
-
}
|
|
1280
|
-
try {
|
|
1281
|
-
return JSON.stringify(errorObject);
|
|
1282
|
-
} catch (err) {
|
|
1283
|
-
return '';
|
|
1284
|
-
}
|
|
1285
|
-
}
|
|
1286
|
-
try {
|
|
1287
|
-
return JSON.stringify(error);
|
|
1288
|
-
} catch (err) {
|
|
1289
|
-
return '';
|
|
1290
|
-
}
|
|
1291
|
-
}, [createTemplateError, editTemplateError, isEditMode]);
|
|
1292
|
-
|
|
1293
|
-
const accountErrorText = useMemo(
|
|
1294
|
-
() => (!accountId ? formatMessage(messages.accountRequired) : ''),
|
|
1295
|
-
[accountId, formatMessage],
|
|
1296
|
-
);
|
|
1297
|
-
|
|
1298
|
-
return (
|
|
1299
|
-
<CapRow className="webpush-container">
|
|
1300
|
-
<CapColumn className="content-section" span={14}>
|
|
1301
|
-
{isFullMode && (
|
|
1302
|
-
<CapRow className="input-group creative-name-container">
|
|
1303
|
-
<CapInput
|
|
1304
|
-
id="webpush-template-name-input"
|
|
1305
|
-
className="webpush-template-name-input"
|
|
1306
|
-
label={formatMessage(messages.creativeName)}
|
|
1307
|
-
placeholder={formatMessage(messages.creativeNamePlaceholder)}
|
|
1308
|
-
value={templateName}
|
|
1309
|
-
onChange={handleTemplateNameChange}
|
|
1310
|
-
size="default"
|
|
1311
|
-
status={templateNameError ? 'error' : ''}
|
|
1312
|
-
help={
|
|
1313
|
-
templateNameError
|
|
1314
|
-
? formatMessage(messages.emptyTemplateErrorMessage)
|
|
1315
|
-
: ''
|
|
1316
|
-
}
|
|
1317
|
-
/>
|
|
1318
|
-
</CapRow>
|
|
1319
|
-
)}
|
|
1320
|
-
{isFullMode && <CapDivider />}
|
|
1321
|
-
<CapRow className="creatives-webpush-title">
|
|
1322
|
-
<CapRow className="tooltip-add-label-container webpush-title-taglist">
|
|
1323
|
-
{titleTagList}
|
|
1324
|
-
</CapRow>
|
|
1325
|
-
<CapHeading type="h3" className="webpush-title">
|
|
1326
|
-
<FormattedMessage {...messages.notificationTitle} />
|
|
1327
|
-
</CapHeading>
|
|
1328
|
-
<CapInput
|
|
1329
|
-
id="webpush-notification-title-input"
|
|
1330
|
-
value={notificationTitle}
|
|
1331
|
-
onChange={handleNotificationTitleChange}
|
|
1332
|
-
placeholder={formatMessage(messages.notificationTitlePlaceholder)}
|
|
1333
|
-
size="default"
|
|
1334
|
-
isRequired
|
|
1335
|
-
maxLength={NOTIFICATION_TITLE_MAX_LENGTH}
|
|
1336
|
-
errorMessage={
|
|
1337
|
-
titleError && (
|
|
1338
|
-
<CapError className="webpush-template-title-error">
|
|
1339
|
-
{titleError}
|
|
1340
|
-
</CapError>
|
|
1341
|
-
)
|
|
1342
|
-
}
|
|
1343
|
-
/>
|
|
1344
|
-
{renderTitleCharacterCount()}
|
|
1345
|
-
</CapRow>
|
|
1346
|
-
<CapRow className="creatives-webpush-message">
|
|
1347
|
-
<CapRow className="tooltip-add-label-container webpush-message-taglist">
|
|
1348
|
-
{messageTagList}
|
|
1349
|
-
</CapRow>
|
|
1350
|
-
<CapHeading type="h3" className="webpush-message">
|
|
1351
|
-
<FormattedMessage {...messages.message} />
|
|
1352
|
-
</CapHeading>
|
|
1353
|
-
<CapInput.TextArea
|
|
1354
|
-
id="webpush-message-input"
|
|
1355
|
-
value={message}
|
|
1356
|
-
onChange={handleMessageChange}
|
|
1357
|
-
placeholder={formatMessage(messages.messagePlaceholder)}
|
|
1358
|
-
size="default"
|
|
1359
|
-
isRequired
|
|
1360
|
-
autosize={{ minRows: 3, maxRows: 5 }}
|
|
1361
|
-
errorMessage={
|
|
1362
|
-
messageError && (
|
|
1363
|
-
<CapError className="webpush-template-message-error">
|
|
1364
|
-
{messageError}
|
|
1365
|
-
</CapError>
|
|
1366
|
-
)
|
|
1367
|
-
}
|
|
1368
|
-
/>
|
|
1369
|
-
{renderMessageCharacterCount()}
|
|
1370
|
-
</CapRow>
|
|
1371
|
-
<CapDivider className="webpush-message-divider" />
|
|
1372
|
-
<CapRow className="creatives-webpush-media">
|
|
1373
|
-
<CapHeading type="h3" className="webpush-media-type">
|
|
1374
|
-
<FormattedMessage {...messages.mediaType} />
|
|
1375
|
-
</CapHeading>
|
|
1376
|
-
<CapSelect.CapCustomSelect
|
|
1377
|
-
width="100%"
|
|
1378
|
-
className="margin-t-4"
|
|
1379
|
-
options={WEBPUSH_MEDIA_TYPES_OPTIONS}
|
|
1380
|
-
value={mediaType}
|
|
1381
|
-
onChange={handleMediaTypeChange}
|
|
1382
|
-
disabled={isAnyUploadActive}
|
|
1383
|
-
/>
|
|
1384
|
-
</CapRow>
|
|
1385
|
-
{mediaType === WEBPUSH_MEDIA_TYPES.IMAGE && (
|
|
1386
|
-
<>
|
|
1387
|
-
<CapRow className="webpush-image-upload-method">
|
|
1388
|
-
<CapRadioGroup
|
|
1389
|
-
options={[
|
|
1390
|
-
{ value: IMAGE_UPLOAD_METHODS.UPLOAD_IMAGE, label: formatMessage(messages.uploadImage) },
|
|
1391
|
-
{ value: IMAGE_UPLOAD_METHODS.ADD_IMAGE_URL, label: formatMessage(messages.addImageUrl) },
|
|
1392
|
-
]}
|
|
1393
|
-
value={imageUploadMethod}
|
|
1394
|
-
onChange={handleImageUploadMethodChange}
|
|
1395
|
-
disabled={isAnyUploadActive}
|
|
1396
|
-
/>
|
|
1397
|
-
</CapRow>
|
|
1398
|
-
{imageUploadMethod === IMAGE_UPLOAD_METHODS.UPLOAD_IMAGE && (
|
|
1399
|
-
<CapRow
|
|
1400
|
-
className="webpush-image-upload-section"
|
|
1401
|
-
style={isMediaSectionLocked ? { pointerEvents: 'none', opacity: 0.5 } : undefined}
|
|
1402
|
-
aria-disabled={isMediaSectionLocked}
|
|
1403
|
-
>
|
|
1404
|
-
{/* Note: image width/height validation will be ignored for the web push channel inside CapImageUpload */}
|
|
1405
|
-
<CapImageUpload
|
|
1406
|
-
allowedExtensionsRegex={ALLOWED_IMAGE_EXTENSIONS_REGEX}
|
|
1407
|
-
imgSize={WEBPUSH_IMG_SIZE}
|
|
1408
|
-
uploadAsset={uploadWebPushAsset}
|
|
1409
|
-
isFullMode={isFullMode}
|
|
1410
|
-
imageSrc={imageSrc}
|
|
1411
|
-
updateImageSrc={setUpdateWebPushImageSrc}
|
|
1412
|
-
updateOnReUpload={updateOnWebPushImageReUpload}
|
|
1413
|
-
index={0}
|
|
1414
|
-
className="cap-custom-image-upload"
|
|
1415
|
-
key="webpush-uploaded-image"
|
|
1416
|
-
imageData={webPush}
|
|
1417
|
-
channel={WEBPUSH}
|
|
1418
|
-
showReUploadButton
|
|
1419
|
-
recommendedDimensions={WEBPUSH_RECOMMENDED_DIMENSIONS}
|
|
1420
|
-
/>
|
|
1421
|
-
</CapRow>
|
|
1422
|
-
)}
|
|
1423
|
-
{imageUploadMethod === IMAGE_UPLOAD_METHODS.ADD_IMAGE_URL && (
|
|
1424
|
-
<CapRow
|
|
1425
|
-
className="webpush-image-url-section"
|
|
1426
|
-
style={isMediaSectionLocked ? { pointerEvents: 'none', opacity: 0.5 } : undefined}
|
|
1427
|
-
aria-disabled={isMediaSectionLocked}
|
|
1428
|
-
>
|
|
1429
|
-
<CapImageUrlUpload
|
|
1430
|
-
uploadAsset={uploadWebPushAsset}
|
|
1431
|
-
imgSize={WEBPUSH_IMG_SIZE}
|
|
1432
|
-
recommendedDimensions={WEBPUSH_RECOMMENDED_DIMENSIONS}
|
|
1433
|
-
sizeLabel={formatMessage(messages.sizeLimit)}
|
|
1434
|
-
formatLabel={formatMessage(messages.formatTypes)}
|
|
1435
|
-
imageUrl={imageUrl}
|
|
1436
|
-
imageSrc={imageSrc}
|
|
1437
|
-
onUrlChange={handleImageUrlChange}
|
|
1438
|
-
onValidationStateChange={handleImageValidationStateChange}
|
|
1439
|
-
onUploadStateChange={handleImageUploadStateChange}
|
|
1440
|
-
isExternalUploading={isImageFieldActive && isUploadingAsset}
|
|
1441
|
-
disabled={isMediaSectionLocked}
|
|
1442
|
-
className="webpush-image-url-upload"
|
|
1443
|
-
fileNamePrefix="webpush-image"
|
|
1444
|
-
/>
|
|
1445
|
-
</CapRow>
|
|
1446
|
-
)}
|
|
1447
|
-
</>
|
|
1448
|
-
)}
|
|
1449
|
-
<CapDivider />
|
|
1450
|
-
<CapRow className="creatives-webpush-brand-icon">
|
|
1451
|
-
<CapHeading type="h3" className="webpush-brand-icon">
|
|
1452
|
-
<FormattedMessage {...messages.brandIconLogo} />
|
|
1453
|
-
</CapHeading>
|
|
1454
|
-
<CapRadioGroup
|
|
1455
|
-
options={brandIconOptions}
|
|
1456
|
-
value={brandIconOption}
|
|
1457
|
-
onChange={handleBrandIconChange}
|
|
1458
|
-
disabled={isAnyUploadActive}
|
|
1459
|
-
/>
|
|
1460
|
-
</CapRow>
|
|
1461
|
-
{brandIconOption === BRAND_ICON_OPTIONS.UPLOAD_IMAGE && (
|
|
1462
|
-
<CapRow
|
|
1463
|
-
className="webpush-brand-icon-upload-section"
|
|
1464
|
-
style={isBrandIconSectionLocked ? { pointerEvents: 'none', opacity: 0.5 } : undefined}
|
|
1465
|
-
aria-disabled={isBrandIconSectionLocked}
|
|
1466
|
-
>
|
|
1467
|
-
{/* Note: image width/height validation will be ignored for the web push channel inside CapImageUpload */}
|
|
1468
|
-
<CapImageUpload
|
|
1469
|
-
allowedExtensionsRegex={ALLOWED_IMAGE_EXTENSIONS_REGEX}
|
|
1470
|
-
imgSize={WEBPUSH_BRAND_ICON_SIZE}
|
|
1471
|
-
uploadAsset={uploadWebPushBrandIconAsset}
|
|
1472
|
-
isFullMode={isFullMode}
|
|
1473
|
-
imageSrc={brandIconSrc}
|
|
1474
|
-
updateImageSrc={setUpdateWebPushBrandIconSrc}
|
|
1475
|
-
updateOnReUpload={updateOnWebPushBrandIconReUpload}
|
|
1476
|
-
index={1}
|
|
1477
|
-
className="cap-custom-image-upload"
|
|
1478
|
-
key="webpush-brand-icon-uploaded-image"
|
|
1479
|
-
imageData={webPush}
|
|
1480
|
-
channel={WEBPUSH_BRAND_ICON}
|
|
1481
|
-
showReUploadButton
|
|
1482
|
-
recommendedDimensions={WEBPUSH_BRAND_ICON_RECOMMENDED_DIMENSIONS}
|
|
1483
|
-
/>
|
|
1484
|
-
</CapRow>
|
|
1485
|
-
)}
|
|
1486
|
-
{brandIconOption === BRAND_ICON_OPTIONS.ADD_IMAGE_URL && (
|
|
1487
|
-
<CapRow
|
|
1488
|
-
className="webpush-brand-icon-url-section"
|
|
1489
|
-
style={isBrandIconSectionLocked ? { pointerEvents: 'none', opacity: 0.5 } : undefined}
|
|
1490
|
-
aria-disabled={isBrandIconSectionLocked}
|
|
1491
|
-
>
|
|
1492
|
-
<CapImageUrlUpload
|
|
1493
|
-
uploadAsset={uploadWebPushBrandIconAsset}
|
|
1494
|
-
imgSize={WEBPUSH_BRAND_ICON_SIZE}
|
|
1495
|
-
recommendedDimensions={WEBPUSH_BRAND_ICON_RECOMMENDED_DIMENSIONS}
|
|
1496
|
-
sizeLabel={formatMessage(messages.sizeLimitBrandIcon)}
|
|
1497
|
-
formatLabel={formatMessage(messages.formatTypes)}
|
|
1498
|
-
imageUrl={brandIconUrl}
|
|
1499
|
-
imageSrc={brandIconSrc}
|
|
1500
|
-
onUrlChange={handleBrandIconUrlChange}
|
|
1501
|
-
onValidationStateChange={handleBrandIconValidationStateChange}
|
|
1502
|
-
onUploadStateChange={handleBrandIconUploadStateChange}
|
|
1503
|
-
isExternalUploading={isBrandIconFieldActive && isUploadingAsset}
|
|
1504
|
-
disabled={isBrandIconSectionLocked}
|
|
1505
|
-
className="webpush-brand-icon-url-upload"
|
|
1506
|
-
fileNamePrefix="webpush-brand-icon"
|
|
1507
|
-
/>
|
|
1508
|
-
</CapRow>
|
|
1509
|
-
)}
|
|
1510
|
-
<CapDivider />
|
|
1511
|
-
<CapRow className="creatives-webpush-buttons-links">
|
|
1512
|
-
<CapHeading type="h3" className="webpush-buttons-links">
|
|
1513
|
-
<FormattedMessage {...messages.buttonsAndLinks} />{' '}
|
|
1514
|
-
<span className="optional-text">
|
|
1515
|
-
<FormattedMessage {...messages.optional} />
|
|
1516
|
-
</span>
|
|
1517
|
-
</CapHeading>
|
|
1518
|
-
<CapHeading type="h4" className="webpush-on-click-behaviour">
|
|
1519
|
-
<FormattedMessage {...messages.onClickBehaviour} />
|
|
1520
|
-
</CapHeading>
|
|
1521
|
-
<CapRadioGroup
|
|
1522
|
-
options={onClickBehaviourOptions}
|
|
1523
|
-
value={onClickBehaviour}
|
|
1524
|
-
onChange={handleOnClickBehaviourChange}
|
|
1525
|
-
/>
|
|
1526
|
-
{onClickBehaviour === ON_CLICK_BEHAVIOUR_OPTIONS.REDIRECT_TO_URL && (
|
|
1527
|
-
<CapInput
|
|
1528
|
-
id="webpush-redirect-url-input"
|
|
1529
|
-
className="webpush-redirect-url-input"
|
|
1530
|
-
placeholder={formatMessage(messages.enterUrl)}
|
|
1531
|
-
value={redirectUrl}
|
|
1532
|
-
onChange={handleRedirectUrlChange}
|
|
1533
|
-
size="default"
|
|
1534
|
-
status={redirectUrlError ? 'error' : ''}
|
|
1535
|
-
help={redirectUrlError || ''}
|
|
1536
|
-
/>
|
|
1537
|
-
)}
|
|
1538
|
-
</CapRow>
|
|
1539
|
-
<CapRow className="creatives-webpush-buttons-section">
|
|
1540
|
-
<CapHeading type="h4" className="webpush-buttons-section-heading">
|
|
1541
|
-
<FormattedMessage {...messages.buttons} />
|
|
1542
|
-
</CapHeading>
|
|
1543
|
-
<ButtonList
|
|
1544
|
-
buttons={buttons}
|
|
1545
|
-
onEdit={handleButtonEdit}
|
|
1546
|
-
onDelete={handleButtonDelete}
|
|
1547
|
-
onReorder={handleButtonReorder}
|
|
1548
|
-
onAddPrimary={handleAddPrimaryButton}
|
|
1549
|
-
onAddSecondary={handleAddSecondaryButton}
|
|
1550
|
-
showAddPrimary={false}
|
|
1551
|
-
showAddSecondary={false}
|
|
1552
|
-
disabled={isAddFlow}
|
|
1553
|
-
disableSecondaryButton={disableSecondaryAddButton}
|
|
1554
|
-
isInlineFormVisible={isEditFlow}
|
|
1555
|
-
inlineFormIndex={isEditFlow ? editingButtonIndex : null}
|
|
1556
|
-
renderInlineForm={isEditFlow ? () => renderButtonForm(true) : null}
|
|
1557
|
-
/>
|
|
1558
|
-
{isAddFlow && buttonBeingAdded && renderButtonForm(false)}
|
|
1559
|
-
{(showAddPrimaryButton || showAddSecondaryButton || showDisabledSecondaryDuringPrimary) && (
|
|
1560
|
-
<div className="button-add-controls">
|
|
1561
|
-
{showAddPrimaryButton && (
|
|
1562
|
-
<CapButton
|
|
1563
|
-
type="flat"
|
|
1564
|
-
onClick={handleAddPrimaryButton}
|
|
1565
|
-
className="add-primary-button button-add-trigger"
|
|
1566
|
-
icon="plus"
|
|
1567
|
-
>
|
|
1568
|
-
<FormattedMessage {...messages.addButton} />
|
|
1569
|
-
</CapButton>
|
|
1570
|
-
)}
|
|
1571
|
-
{showAddSecondaryButton && (
|
|
1572
|
-
<CapButton
|
|
1573
|
-
type="flat"
|
|
1574
|
-
onClick={handleAddSecondaryButton}
|
|
1575
|
-
className="add-secondary-button button-add-trigger"
|
|
1576
|
-
icon="plus"
|
|
1577
|
-
>
|
|
1578
|
-
<FormattedMessage {...messages.addButton} />
|
|
1579
|
-
</CapButton>
|
|
1580
|
-
)}
|
|
1581
|
-
{showDisabledSecondaryDuringPrimary && (
|
|
1582
|
-
<CapButton
|
|
1583
|
-
type="flat"
|
|
1584
|
-
className="add-secondary-button button-add-trigger"
|
|
1585
|
-
icon="plus"
|
|
1586
|
-
disabled
|
|
1587
|
-
>
|
|
1588
|
-
<FormattedMessage {...messages.addButton} />
|
|
1589
|
-
</CapButton>
|
|
1590
|
-
)}
|
|
1591
|
-
</div>
|
|
1592
|
-
)}
|
|
1593
|
-
</CapRow>
|
|
1594
|
-
<CapRow className="creatives-webpush-actions">
|
|
1595
|
-
<CapButton
|
|
1596
|
-
type="primary"
|
|
1597
|
-
onClick={handleSave}
|
|
1598
|
-
disabled={isSaveDisabled}
|
|
1599
|
-
>
|
|
1600
|
-
{formatMessage(messages.saveTemplate)}
|
|
1601
|
-
</CapButton>
|
|
1602
|
-
</CapRow>
|
|
1603
|
-
{(createTemplateError || editTemplateError) && (
|
|
1604
|
-
<CapRow>
|
|
1605
|
-
<CapError className="webpush-template-error">
|
|
1606
|
-
{errorText}
|
|
1607
|
-
</CapError>
|
|
1608
|
-
</CapRow>
|
|
1609
|
-
)}
|
|
1610
|
-
{accountErrorText && (
|
|
1611
|
-
<CapRow>
|
|
1612
|
-
<CapError className="webpush-template-account-error">
|
|
1613
|
-
{accountErrorText}
|
|
1614
|
-
</CapError>
|
|
1615
|
-
</CapRow>
|
|
1616
|
-
)}
|
|
1617
|
-
</CapColumn>
|
|
1618
|
-
<CapColumn className="preview-section" span={10}>
|
|
1619
|
-
<WebPushPreview
|
|
1620
|
-
notificationTitle={notificationTitle}
|
|
1621
|
-
notificationBody={message}
|
|
1622
|
-
url={previewUrl}
|
|
1623
|
-
imageSrc={imageSrc}
|
|
1624
|
-
brandIconSrc={brandIconSrc}
|
|
1625
|
-
/>
|
|
1626
|
-
</CapColumn>
|
|
1627
|
-
</CapRow>
|
|
1628
|
-
);
|
|
1629
|
-
};
|
|
1630
|
-
|
|
1631
|
-
WebPushCreate.propTypes = {
|
|
1632
|
-
isFullMode: PropTypes.bool,
|
|
1633
|
-
handleClose: PropTypes.func,
|
|
1634
|
-
intl: intlShape.isRequired,
|
|
1635
|
-
webPushActions: PropTypes.object,
|
|
1636
|
-
createTemplateInProgress: PropTypes.bool,
|
|
1637
|
-
createTemplateError: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
|
|
1638
|
-
editTemplateInProgress: PropTypes.bool,
|
|
1639
|
-
editTemplateError: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
|
|
1640
|
-
accountData: PropTypes.object,
|
|
1641
|
-
webPush: PropTypes.object,
|
|
1642
|
-
onCreateComplete: PropTypes.func,
|
|
1643
|
-
getFormData: PropTypes.func,
|
|
1644
|
-
isGetFormData: PropTypes.bool,
|
|
1645
|
-
templateData: PropTypes.object,
|
|
1646
|
-
creativesMode: PropTypes.string,
|
|
1647
|
-
params: PropTypes.object,
|
|
1648
|
-
globalActions: PropTypes.object,
|
|
1649
|
-
location: PropTypes.object,
|
|
1650
|
-
metaEntities: PropTypes.object,
|
|
1651
|
-
injectedTags: PropTypes.object,
|
|
1652
|
-
getDefaultTags: PropTypes.string,
|
|
1653
|
-
supportedTags: PropTypes.array,
|
|
1654
|
-
forwardedTags: PropTypes.object,
|
|
1655
|
-
selectedOfferDetails: PropTypes.array,
|
|
1656
|
-
eventContextTags: PropTypes.array,
|
|
1657
|
-
};
|
|
1658
|
-
|
|
1659
|
-
WebPushCreate.defaultProps = {
|
|
1660
|
-
isFullMode: true,
|
|
1661
|
-
handleClose: () => { },
|
|
1662
|
-
webPushActions: {},
|
|
1663
|
-
createTemplateInProgress: false,
|
|
1664
|
-
createTemplateError: '',
|
|
1665
|
-
accountData: {},
|
|
1666
|
-
webPush: {},
|
|
1667
|
-
onCreateComplete: () => { },
|
|
1668
|
-
getFormData: null,
|
|
1669
|
-
isGetFormData: false,
|
|
1670
|
-
templateData: null,
|
|
1671
|
-
creativesMode: 'createTemplate',
|
|
1672
|
-
params: null,
|
|
1673
|
-
globalActions: {},
|
|
1674
|
-
location: null,
|
|
1675
|
-
metaEntities: null,
|
|
1676
|
-
injectedTags: {},
|
|
1677
|
-
getDefaultTags: '',
|
|
1678
|
-
supportedTags: [],
|
|
1679
|
-
forwardedTags: {},
|
|
1680
|
-
selectedOfferDetails: [],
|
|
1681
|
-
eventContextTags: [],
|
|
1682
|
-
};
|
|
1683
|
-
|
|
1684
|
-
const mapStateToProps = createStructuredSelector({
|
|
1685
|
-
webPush: makeSelectWebPush(),
|
|
1686
|
-
createTemplateInProgress: makeSelectCreateTemplateInProgress(),
|
|
1687
|
-
createTemplateError: makeSelectCreateError(),
|
|
1688
|
-
editTemplateInProgress: makeSelectEditTemplateInProgress(),
|
|
1689
|
-
editTemplateError: makeSelectEditError(),
|
|
1690
|
-
metaEntities: makeSelectMetaEntities(),
|
|
1691
|
-
injectedTags: setInjectedTags(),
|
|
1692
|
-
accountData: createSelector(
|
|
1693
|
-
(state) => state.get('templates'),
|
|
1694
|
-
(templatesState) => {
|
|
1695
|
-
if (!templatesState) {
|
|
1696
|
-
return {};
|
|
1697
|
-
}
|
|
1698
|
-
const templates = templatesState.toJS();
|
|
1699
|
-
return templates?.selectedWebPushAccount || {};
|
|
1700
|
-
},
|
|
1701
|
-
),
|
|
1702
|
-
});
|
|
1703
|
-
|
|
1704
|
-
const mapDispatchToProps = (dispatch) => ({
|
|
1705
|
-
webPushActions: bindActionCreators(actions, dispatch),
|
|
1706
|
-
});
|
|
1707
|
-
|
|
1708
|
-
const withSaga = injectSaga({
|
|
1709
|
-
key: 'webPush',
|
|
1710
|
-
saga: webPushSagas,
|
|
1711
|
-
mode: DAEMON,
|
|
1712
|
-
});
|
|
1713
|
-
|
|
1714
|
-
const withReducer = injectReducer({
|
|
1715
|
-
key: 'webPush',
|
|
1716
|
-
reducer: webPushReducer,
|
|
1717
|
-
});
|
|
1718
|
-
|
|
1719
|
-
export default withCreatives({
|
|
1720
|
-
WrappedComponent: injectIntl(WebPushCreate),
|
|
1721
|
-
mapStateToProps,
|
|
1722
|
-
mapDispatchToProps,
|
|
1723
|
-
userAuth: true,
|
|
1724
|
-
sagas: [withSaga],
|
|
1725
|
-
reducers: [withReducer],
|
|
1726
|
-
});
|
|
1727
|
-
|