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