@capillarytech/creatives-library 8.0.130 → 8.0.132
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/containers/App/constants.js +1 -0
- package/containers/Login/index.js +1 -2
- package/package.json +1 -1
- package/services/api.js +5 -0
- package/tests/integration/TemplateCreation/TemplateCreation.integration.test.js +8 -3
- package/tests/integration/TemplateCreation/api-response.js +5 -0
- package/tests/integration/TemplateCreation/msw-handler.js +42 -63
- package/utils/common.js +7 -0
- package/utils/commonUtils.js +2 -6
- package/utils/createMobilePushPayload.js +322 -0
- package/utils/tests/createMobilePushPayload.test.js +1054 -0
- package/v2Components/CapDeviceContent/index.js +1 -1
- package/v2Components/CapImageUpload/index.js +57 -44
- package/v2Components/CapInAppCTA/index.js +1 -0
- package/v2Components/CapMpushCTA/constants.js +25 -0
- package/v2Components/CapMpushCTA/index.js +403 -0
- package/v2Components/CapMpushCTA/index.scss +95 -0
- package/v2Components/CapMpushCTA/messages.js +101 -0
- package/v2Components/CapTagList/index.js +178 -121
- package/v2Components/CapVideoUpload/constants.js +3 -0
- package/v2Components/CapVideoUpload/index.js +182 -115
- package/v2Components/CapVideoUpload/messages.js +16 -0
- package/v2Components/Carousel/index.js +15 -13
- package/v2Components/ErrorInfoNote/style.scss +1 -0
- package/v2Components/MobilePushPreviewV2/index.js +57 -12
- package/v2Components/TemplatePreview/_templatePreview.scss +218 -74
- package/v2Components/TemplatePreview/assets/images/Android_With_date_and_time.svg +29 -0
- package/v2Components/TemplatePreview/assets/images/android.svg +9 -0
- package/v2Components/TemplatePreview/assets/images/iOS_With_date_and_time.svg +26 -0
- package/v2Components/TemplatePreview/assets/images/ios.svg +9 -0
- package/v2Components/TemplatePreview/index.js +234 -107
- package/v2Components/TemplatePreview/messages.js +4 -0
- package/v2Components/TemplatePreview/tests/__snapshots__/index.test.js.snap +10 -10
- package/v2Containers/CreativesContainer/SlideBoxContent.js +127 -62
- package/v2Containers/CreativesContainer/index.js +193 -136
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +0 -22
- package/v2Containers/InApp/constants.js +1 -0
- package/v2Containers/InApp/index.js +13 -13
- package/v2Containers/Line/Container/tests/__snapshots__/index.test.js.snap +4748 -4658
- package/v2Containers/Login/index.js +1 -2
- package/v2Containers/MobilePush/Create/index.js +1 -0
- package/v2Containers/MobilePush/commonMethods.js +7 -14
- package/v2Containers/MobilePush/tests/commonMethods.test.js +401 -0
- package/v2Containers/MobilePushNew/actions.js +116 -0
- package/v2Containers/MobilePushNew/components/CtaButtons.js +183 -0
- package/v2Containers/MobilePushNew/components/MediaUploaders.js +835 -0
- package/v2Containers/MobilePushNew/components/PlatformContentFields.js +346 -0
- package/v2Containers/MobilePushNew/components/index.js +5 -0
- package/v2Containers/MobilePushNew/components/tests/CtaButtons.test.js +565 -0
- package/v2Containers/MobilePushNew/components/tests/MediaUploaders.test.js +3180 -0
- package/v2Containers/MobilePushNew/components/tests/PlatformContentFields.test.js +654 -0
- package/v2Containers/MobilePushNew/constants.js +116 -0
- package/v2Containers/MobilePushNew/hooks/tests/usePlatformSync.test.js +1462 -0
- package/v2Containers/MobilePushNew/hooks/tests/useUpload.test.js +1459 -0
- package/v2Containers/MobilePushNew/hooks/usePlatformSync.js +366 -0
- package/v2Containers/MobilePushNew/hooks/useUpload.js +740 -0
- package/v2Containers/MobilePushNew/index.js +2158 -0
- package/v2Containers/MobilePushNew/index.scss +308 -0
- package/v2Containers/MobilePushNew/messages.js +272 -0
- package/v2Containers/MobilePushNew/reducer.js +160 -0
- package/v2Containers/MobilePushNew/sagas.js +193 -0
- package/v2Containers/MobilePushNew/selectors.js +55 -0
- package/v2Containers/MobilePushNew/tests/reducer.test.js +741 -0
- package/v2Containers/MobilePushNew/tests/sagas.test.js +864 -0
- package/v2Containers/MobilePushNew/tests/selectors.test.js +665 -0
- package/v2Containers/MobilePushNew/tests/utils.test.js +421 -0
- package/v2Containers/MobilePushNew/utils.js +84 -0
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +1176 -976
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +684 -424
- package/v2Containers/TagList/index.js +56 -10
- package/v2Containers/Templates/_templates.scss +100 -1
- package/v2Containers/Templates/index.js +170 -31
- package/v2Containers/Templates/messages.js +8 -0
- package/v2Containers/Templates/sagas.js +1 -0
- package/v2Containers/Whatsapp/constants.js +1 -0
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +3992 -3677
- package/assets/loading_img.gif +0 -0
|
@@ -39,12 +39,14 @@ export class TagList extends React.Component { // eslint-disable-line react/pref
|
|
|
39
39
|
loading: false,
|
|
40
40
|
tags: [],
|
|
41
41
|
tagsError: false,
|
|
42
|
+
currentContext: null, // Track current context to detect changes
|
|
42
43
|
};
|
|
43
44
|
this.renderTags = this.renderTags.bind(this);
|
|
44
45
|
this.populateTags = this.populateTags.bind(this);
|
|
45
46
|
this.populateTagForChildren = this.populateTagForChildren.bind(this);
|
|
46
47
|
this.transformInjectedTags = this.transformInjectedTags.bind(this);
|
|
47
48
|
this.transformCouponTags = this.transformCouponTags.bind(this);
|
|
49
|
+
this.loadingTimeout = null; // Add timeout reference
|
|
48
50
|
}
|
|
49
51
|
|
|
50
52
|
componentDidMount() {
|
|
@@ -52,33 +54,72 @@ export class TagList extends React.Component { // eslint-disable-line react/pref
|
|
|
52
54
|
}
|
|
53
55
|
|
|
54
56
|
componentWillReceiveProps(nextProps) {
|
|
55
|
-
|
|
57
|
+
// Set loading to true in these scenarios:
|
|
58
|
+
// 1. Both injectedTags and tags are empty (initial load)
|
|
59
|
+
// 2. Context change is happening (detected by different tag arrays)
|
|
60
|
+
const { injectedTags: currentInjectedTags, tags: currentTags } = this.props;
|
|
61
|
+
const { injectedTags: nextInjectedTags, tags: nextTags, fetchingSchemaError } = nextProps;
|
|
62
|
+
|
|
63
|
+
const isInitialLoad = _.isEmpty(currentInjectedTags) && _.isEmpty(currentTags);
|
|
64
|
+
const isContextChange = !_.isEqual(nextTags, currentTags) && !_.isEmpty(currentTags);
|
|
65
|
+
|
|
66
|
+
if (isInitialLoad || isContextChange) {
|
|
56
67
|
this.setState({loading: true});
|
|
57
68
|
}
|
|
58
|
-
|
|
69
|
+
|
|
70
|
+
// Only reset loading for injectedTags changes if we're not currently loading due to context change
|
|
71
|
+
if (!_.isEqual(nextInjectedTags, currentInjectedTags) && !this.state.loading) {
|
|
59
72
|
this.setState({loading: false});
|
|
73
|
+
this.clearLoadingTimeout();
|
|
60
74
|
}
|
|
61
|
-
|
|
75
|
+
|
|
76
|
+
if (!_.isEqual(nextTags, currentTags)) {
|
|
62
77
|
this.setState({loading: false});
|
|
78
|
+
this.clearLoadingTimeout();
|
|
63
79
|
}
|
|
64
|
-
if (
|
|
65
|
-
this.setState({tagsError:
|
|
80
|
+
if (fetchingSchemaError) {
|
|
81
|
+
this.setState({tagsError: fetchingSchemaError, loading: false});
|
|
82
|
+
this.clearLoadingTimeout();
|
|
66
83
|
}
|
|
67
84
|
}
|
|
68
85
|
|
|
69
86
|
componentDidUpdate(prevProps) {
|
|
70
|
-
|
|
87
|
+
const { tags, injectedTags, selectedOfferDetails } = this.props;
|
|
88
|
+
const { tags: prevTags, injectedTags: prevInjectedTags, selectedOfferDetails: prevSelectedOfferDetails } = prevProps;
|
|
89
|
+
|
|
90
|
+
if (tags !== prevTags || injectedTags !== prevInjectedTags || selectedOfferDetails !== prevSelectedOfferDetails) {
|
|
71
91
|
this.generateTags(this.props);
|
|
72
92
|
}
|
|
73
93
|
}
|
|
74
94
|
|
|
95
|
+
componentWillUnmount() {
|
|
96
|
+
this.clearLoadingTimeout();
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
clearLoadingTimeout = () => {
|
|
100
|
+
if (this.loadingTimeout) {
|
|
101
|
+
clearTimeout(this.loadingTimeout);
|
|
102
|
+
this.loadingTimeout = null;
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
|
|
75
106
|
onSelect = (selectedKeys) => {
|
|
76
|
-
this.props
|
|
107
|
+
const { onTagSelect } = this.props;
|
|
108
|
+
onTagSelect(selectedKeys[0]);
|
|
77
109
|
};
|
|
78
110
|
|
|
79
111
|
getTagsforContext = (data) => {
|
|
80
|
-
//
|
|
81
|
-
this.
|
|
112
|
+
// Set loading state when context change is requested
|
|
113
|
+
this.setState({loading: true, currentContext: data});
|
|
114
|
+
|
|
115
|
+
// Set a timeout to prevent infinite loading (fallback safety)
|
|
116
|
+
this.clearLoadingTimeout();
|
|
117
|
+
this.loadingTimeout = setTimeout(() => {
|
|
118
|
+
this.setState({loading: false});
|
|
119
|
+
}, 5000); // Reduced timeout to 5 seconds for better UX
|
|
120
|
+
|
|
121
|
+
const { onContextChange } = this.props;
|
|
122
|
+
onContextChange(data);
|
|
82
123
|
}
|
|
83
124
|
|
|
84
125
|
generateTags = (props) => {
|
|
@@ -159,7 +200,8 @@ export class TagList extends React.Component { // eslint-disable-line react/pref
|
|
|
159
200
|
//Form tags object with tag headers
|
|
160
201
|
_.forEach(tagsList, (temp) => {
|
|
161
202
|
const tag = temp.definition;
|
|
162
|
-
const {
|
|
203
|
+
const { intl } = this.props;
|
|
204
|
+
const { locale: userLocale } = intl || {};
|
|
163
205
|
|
|
164
206
|
// Check if the tag.value should be skipped based on feature control
|
|
165
207
|
if (_.includes(excludedTags, tag.value)) {
|
|
@@ -360,6 +402,10 @@ TagList.propTypes = {
|
|
|
360
402
|
disabled: PropTypes.bool,
|
|
361
403
|
fetchingSchemaError: PropTypes.bool,
|
|
362
404
|
eventContextTags: PropTypes.array,
|
|
405
|
+
intl: PropTypes.shape({
|
|
406
|
+
formatMessage: PropTypes.func.isRequired,
|
|
407
|
+
locale: PropTypes.string,
|
|
408
|
+
}).isRequired,
|
|
363
409
|
};
|
|
364
410
|
|
|
365
411
|
const mapStateToProps = createStructuredSelector({
|
|
@@ -219,6 +219,105 @@
|
|
|
219
219
|
}
|
|
220
220
|
}
|
|
221
221
|
}
|
|
222
|
+
|
|
223
|
+
.MOBILEPUSH {
|
|
224
|
+
.ant-card-body {
|
|
225
|
+
padding: 0;
|
|
226
|
+
background-color: $CAP_WHITE;
|
|
227
|
+
border-top: 1px solid $CAP_COLOR_16;
|
|
228
|
+
.ant-card-meta {
|
|
229
|
+
background-color: $CAP_G09;
|
|
230
|
+
.ant-card-meta-description {
|
|
231
|
+
.mobilepush-container {
|
|
232
|
+
background-color: $CAP_WHITE;
|
|
233
|
+
padding: $CAP_SPACE_12;
|
|
234
|
+
.app-header {
|
|
235
|
+
color: #5D5D5D;
|
|
236
|
+
font-weight: 600;
|
|
237
|
+
padding: 0.285rem 0.571rem 0.285rem 0.571rem;
|
|
238
|
+
display: flex;
|
|
239
|
+
align-items: center;
|
|
240
|
+
justify-content: space-between;
|
|
241
|
+
.app-header-left{
|
|
242
|
+
display: flex;
|
|
243
|
+
align-items: center;
|
|
244
|
+
div {
|
|
245
|
+
word-break: break-word;
|
|
246
|
+
}
|
|
247
|
+
.app-icon {
|
|
248
|
+
width: 0.857rem;
|
|
249
|
+
height: 0.857rem;
|
|
250
|
+
border-radius: 50%;
|
|
251
|
+
background-color: #737070;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
.mobilepush-message {
|
|
256
|
+
padding-left: 1.65rem;
|
|
257
|
+
}
|
|
258
|
+
.mobilepush-image {
|
|
259
|
+
width: 100%;
|
|
260
|
+
height: 120px;
|
|
261
|
+
margin-top: 10px;
|
|
262
|
+
}
|
|
263
|
+
.mobilepush-image-padding {
|
|
264
|
+
padding-left: 1.65rem;
|
|
265
|
+
}
|
|
266
|
+
.scroll-container {
|
|
267
|
+
overflow-x: auto;
|
|
268
|
+
display: flex;
|
|
269
|
+
padding-top: $CAP_SPACE_06;
|
|
270
|
+
padding-right: $CAP_SPACE_06;
|
|
271
|
+
white-space: nowrap;
|
|
272
|
+
scrollbar-width: none; // Hide scrollbar in Firefox
|
|
273
|
+
&::-webkit-scrollbar {
|
|
274
|
+
display: none; // Hide scrollbar in Chrome/Safari/Opera
|
|
275
|
+
}
|
|
276
|
+
overflow: hidden;
|
|
277
|
+
height: 100%;
|
|
278
|
+
width: 100%;
|
|
279
|
+
margin-left: 1.65rem;
|
|
280
|
+
.whatsapp-carousel-container {
|
|
281
|
+
padding: $CAP_SPACE_04 0px $CAP_SPACE_08;
|
|
282
|
+
border-radius: $CAP_SPACE_06;
|
|
283
|
+
background-color: $CAP_WHITE;
|
|
284
|
+
width: 80%;
|
|
285
|
+
flex-shrink: 0;
|
|
286
|
+
white-space: pre-wrap;
|
|
287
|
+
word-break: break-word;
|
|
288
|
+
overflow: auto;
|
|
289
|
+
text-align: left;
|
|
290
|
+
margin: 0;
|
|
291
|
+
.whatsapp-carousel-card {
|
|
292
|
+
margin: $CAP_SPACE_02 $CAP_SPACE_02 $CAP_SPACE_01 $CAP_SPACE_02;
|
|
293
|
+
.whatsapp-carousel-body {
|
|
294
|
+
margin-bottom: $CAP_SPACE_08;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
.actions{
|
|
300
|
+
background-color: #ffffff;
|
|
301
|
+
height: auto;
|
|
302
|
+
padding: $CAP_SPACE_08;
|
|
303
|
+
text-align: center;
|
|
304
|
+
display: flex;
|
|
305
|
+
flex-direction: column;
|
|
306
|
+
align-items: center;
|
|
307
|
+
justify-content: center;
|
|
308
|
+
gap: $CAP_SPACE_08;
|
|
309
|
+
.action{
|
|
310
|
+
font-size: $FONT_SIZE_S;
|
|
311
|
+
font-weight: 600;
|
|
312
|
+
color: #1970DA;
|
|
313
|
+
height: 1.25rem;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
222
321
|
}
|
|
223
322
|
|
|
224
323
|
.create-new-link{
|
|
@@ -502,7 +601,7 @@
|
|
|
502
601
|
}
|
|
503
602
|
}
|
|
504
603
|
.iphone-push-message-Container{
|
|
505
|
-
top:
|
|
604
|
+
top: 10%;
|
|
506
605
|
.message-pop{
|
|
507
606
|
border-radius: 4px;
|
|
508
607
|
word-wrap: break-word;
|
|
@@ -12,7 +12,7 @@ import styled from 'styled-components';
|
|
|
12
12
|
import {injectIntl, intlShape, FormattedMessage } from 'react-intl';
|
|
13
13
|
import { createStructuredSelector } from 'reselect';
|
|
14
14
|
import moment from "moment";
|
|
15
|
-
|
|
15
|
+
|
|
16
16
|
import get from 'lodash/get';
|
|
17
17
|
import isEmpty from 'lodash/isEmpty';
|
|
18
18
|
import isEqual from 'lodash/isEqual';
|
|
@@ -50,26 +50,26 @@ import {
|
|
|
50
50
|
CapImage,
|
|
51
51
|
CapStatus,
|
|
52
52
|
CapColoredTag,
|
|
53
|
-
CapSpin
|
|
53
|
+
CapSpin,
|
|
54
|
+
CapCard,
|
|
55
|
+
CapColumn,
|
|
56
|
+
CapCarousel
|
|
54
57
|
} from "@capillarytech/cap-ui-library";
|
|
55
58
|
import { makeSelectTemplates, makeSelectTemplatesResponse } from './selectors';
|
|
56
|
-
import { makeSelectCreate as makeSelectCreateSms} from '../Sms/Create/selectors';
|
|
59
|
+
import { makeSelectCreate as makeSelectCreateSms } from '../Sms/Create/selectors';
|
|
57
60
|
import { makeSelectCreate as makeSelectCreateMobilePush } from '../MobilePush/Create/selectors';
|
|
58
|
-
import {
|
|
61
|
+
import { makeSelectMobilePushNew } from '../MobilePushNew/selectors';
|
|
59
62
|
import { makeSelectEbill as makeSelectCreateEbill } from '../Ebill/selectors';
|
|
60
63
|
import { makeSelectEmail as makeSelectCreateEmail } from '../Email/selectors';
|
|
61
64
|
import { makeSelectEdit } from '../Sms/Edit/selectors';
|
|
62
65
|
import { makeSelectLine } from '../Line/Container/selectors';
|
|
63
66
|
import { makeSelectViber } from '../Viber/selectors';
|
|
64
67
|
import { makeSelectZalo } from '../Zalo/selectors';
|
|
65
|
-
import {
|
|
66
|
-
import { getObjFromQueryParams } from '../../utils/v2common';
|
|
67
|
-
import messages from './messages';
|
|
68
|
-
import {checkUnicode} from '../../utils/smsCharCountV2';
|
|
68
|
+
import { makeSelectInApp } from '../InApp/selectors';
|
|
69
69
|
import * as actions from './actions';
|
|
70
70
|
import * as smsActions from '../Sms/Create/actions';
|
|
71
71
|
import * as mobilepushActions from '../MobilePush/Create/actions';
|
|
72
|
-
import * as
|
|
72
|
+
import * as mobilePushNewActions from '../MobilePushNew/actions';
|
|
73
73
|
import * as smsEditActions from '../Sms/Edit/actions';
|
|
74
74
|
import * as ebillActions from '../Ebill/actions';
|
|
75
75
|
import * as emailActions from '../Email/actions';
|
|
@@ -79,11 +79,16 @@ import * as facebookActions from '../Facebook/actions';
|
|
|
79
79
|
import * as whatsappActions from '../Whatsapp/actions';
|
|
80
80
|
import * as rcsActions from '../Rcs/actions';
|
|
81
81
|
import * as zaloActions from '../Zalo/actions';
|
|
82
|
+
import * as inAppActions from '../InApp/actions';
|
|
83
|
+
import * as globalActions from '../Cap/actions';
|
|
84
|
+
import { makeSelectAuthenticated } from '../Cap/selectors';
|
|
85
|
+
import { UserIsAuthenticated } from '../../utils/authWrapper';
|
|
86
|
+
import { getObjFromQueryParams } from '../../utils/v2common';
|
|
87
|
+
import messages from './messages';
|
|
88
|
+
import {checkUnicode} from '../../utils/smsCharCountV2';
|
|
82
89
|
import CardGrid from '../../v2Components/CardGrid';
|
|
83
90
|
import config from '../../config/app';
|
|
84
91
|
import './_templates.scss';
|
|
85
|
-
import * as globalActions from '../Cap/actions';
|
|
86
|
-
import { makeSelectAuthenticated } from '../Cap/selectors';
|
|
87
92
|
import * as commonUtil from '../../utils/common';
|
|
88
93
|
import Pagination from '../../v2Components/Pagination';
|
|
89
94
|
import EmailPreview from '../../v2Components/EmailPreview';
|
|
@@ -117,6 +122,7 @@ import {
|
|
|
117
122
|
HOST_ICS,
|
|
118
123
|
IMAGE,
|
|
119
124
|
VIDEO,
|
|
125
|
+
GIF,
|
|
120
126
|
} from '../Whatsapp/constants';
|
|
121
127
|
import { INAPP_LAYOUT_DETAILS } from '../InApp/constants';
|
|
122
128
|
import { ZALO_STATUS_OPTIONS, ZALO_STATUSES } from '../Zalo/constants';
|
|
@@ -149,6 +155,9 @@ import { compose } from 'redux';
|
|
|
149
155
|
import { v2TemplateSaga } from './sagas';
|
|
150
156
|
import injectSaga from '../../utils/injectSaga';
|
|
151
157
|
import { DAEMON } from '@capillarytech/vulcan-react-sdk/utils/sagaInjectorTypes';
|
|
158
|
+
import { v2MobilePushSagas } from '../MobilePushNew/sagas';
|
|
159
|
+
import { AUTO_CAROUSEL, BIG_PICTURE, FILMSTRIP_CAROUSEL, MANUAL_CAROUSEL } from '../MobilePushNew/constants';
|
|
160
|
+
const withMobilePushNewSaga = injectSaga({ key: 'mobilePushNew', saga: v2MobilePushSagas, mode: DAEMON });
|
|
152
161
|
|
|
153
162
|
const { timeTracker } = GA;
|
|
154
163
|
const {CapCustomCardList} = CapCustomCard;
|
|
@@ -237,28 +246,29 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
237
246
|
searchedZaloTemplates: [],
|
|
238
247
|
searchingZaloTemplate: false,
|
|
239
248
|
zaloPreviewItemId: {},
|
|
249
|
+
uploadInProgress: false,
|
|
250
|
+
deleteConfirmationModal: false,
|
|
251
|
+
templateToDelete: {},
|
|
252
|
+
edmDefaultTemplateSelection: false,
|
|
253
|
+
edmSelectedTemplateId: '',
|
|
254
|
+
edmEmailPreview: false,
|
|
255
|
+
emailPreviewDevice: 'desktop',
|
|
256
|
+
// Add flag to prevent duplicate API calls
|
|
257
|
+
isProcessingEditResponse: false,
|
|
240
258
|
};
|
|
241
|
-
|
|
259
|
+
this.getAllTemplates = this.getAllTemplates.bind(this);
|
|
260
|
+
this.createTemplate = this.createTemplate.bind(this);
|
|
261
|
+
this.searchTemplate = this.searchTemplate.bind(this);
|
|
262
|
+
this.handleSortBy = this.handleSortBy.bind(this);
|
|
263
|
+
this.duplicateTemplate = this.duplicateTemplate.bind(this);
|
|
264
|
+
this.deleteTemplate = this.deleteTemplate.bind(this);
|
|
242
265
|
this.handleOnHoverItem = this.handleOnHoverItem.bind(this);
|
|
243
266
|
this.handleOnItemClick = this.handleOnItemClick.bind(this);
|
|
244
267
|
this.handleEditClick = this.handleEditClick.bind(this);
|
|
245
268
|
this.handlePreviewClick = this.handlePreviewClick.bind(this);
|
|
246
|
-
this.createTemplate = this.createTemplate.bind(this);
|
|
247
|
-
this.duplicateTemplate = this.duplicateTemplate.bind(this);
|
|
248
|
-
this.deleteTemplate = this.deleteTemplate.bind(this);
|
|
249
|
-
this.togglePreview = this.togglePreview.bind(this);
|
|
250
|
-
this.searchTemplate = this.searchTemplate.bind(this);
|
|
251
|
-
this.handleSortBy = this.handleSortBy.bind(this);
|
|
252
|
-
this.getCurrentWindow = this.getCurrentWindow.bind(this);
|
|
253
269
|
this.handleFrameTasks = this.handleFrameTasks.bind(this);
|
|
254
|
-
this.startTemplateCreation = this.startTemplateCreation.bind(this);
|
|
255
|
-
this.startLoading = this.startLoading.bind(this);
|
|
256
|
-
this.prepareWeChatPreviewData = this.prepareWeChatPreviewData.bind(this);
|
|
257
|
-
this.prepareWeChatMappedPreviewData = this.prepareWeChatMappedPreviewData.bind(this);
|
|
258
270
|
this.onAccountSelect = this.onAccountSelect.bind(this);
|
|
259
|
-
this.
|
|
260
|
-
this.menuOnClickEvent = this.menuOnClickEvent.bind(this);
|
|
261
|
-
this.delayTimer = 0;
|
|
271
|
+
this.onAccountSelect = this.onAccountSelect.bind(this);
|
|
262
272
|
}
|
|
263
273
|
|
|
264
274
|
// This function is to map the selected source account identifier and the connectionProperties data of domainPropertiesData object to get the hostName.
|
|
@@ -398,6 +408,7 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
398
408
|
window.addEventListener("message", this.handleFrameTasks);
|
|
399
409
|
}
|
|
400
410
|
componentWillReceiveProps(nextProps = {}) {
|
|
411
|
+
|
|
401
412
|
const params = {
|
|
402
413
|
name: this.state.searchText,
|
|
403
414
|
sortBy: this.state.sortBy,
|
|
@@ -567,6 +578,31 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
567
578
|
this.props.lineActions.clearCreateResponse();
|
|
568
579
|
}
|
|
569
580
|
|
|
581
|
+
// Check for MobilePushNew edit response - prevent duplicate calls
|
|
582
|
+
if (selectedChannel === MOBILE_PUSH_LOWERCASE && nextProps.MobilePushNew && nextProps.MobilePushNew.editResponse && nextProps.MobilePushNew.editResponse.templateId && nextProps.MobilePushNew.editResponse.templateId !== '' && !this.state.isProcessingEditResponse) {
|
|
583
|
+
// Set flag to prevent duplicate processing
|
|
584
|
+
this.setState({ isProcessingEditResponse: true });
|
|
585
|
+
|
|
586
|
+
const message = `${this.state.channel} ${this.props.intl.formatMessage(messages.templateUpdateSuccess)}`;
|
|
587
|
+
|
|
588
|
+
CapNotification.success({
|
|
589
|
+
key: 'editSuccess',
|
|
590
|
+
message
|
|
591
|
+
});
|
|
592
|
+
|
|
593
|
+
this.getAllTemplates({params, resetPage: true});
|
|
594
|
+
|
|
595
|
+
this.props.mobilePushNewActions.clearData();
|
|
596
|
+
|
|
597
|
+
this.props.mobilePushNewActions.clearEditResponse();
|
|
598
|
+
|
|
599
|
+
// Reset flag after a delay to allow for next edit
|
|
600
|
+
setTimeout(() => {
|
|
601
|
+
this.setState({ isProcessingEditResponse: false });
|
|
602
|
+
}, 1000);
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
|
|
570
606
|
|
|
571
607
|
if (nextProps.Create && this.props.Create && nextProps.Create.createTemplateError && !isEqual(nextProps.Create.createTemplateError, this.props.Create.createTemplateError)) {
|
|
572
608
|
const message = this.props.intl.formatMessage(messages.somethingWentWrong);
|
|
@@ -1238,6 +1274,99 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
1238
1274
|
break;
|
|
1239
1275
|
}
|
|
1240
1276
|
case MOBILE_PUSH:
|
|
1277
|
+
if (!commonUtil.hasNewMobilePushFeatureEnabled()) {
|
|
1278
|
+
templateData.content = template;
|
|
1279
|
+
} else {
|
|
1280
|
+
const mpushData = get(template, 'versions.base', template);
|
|
1281
|
+
const androidData = get(mpushData, 'ANDROID') || get(mpushData, 'androidContent');
|
|
1282
|
+
const iosData = get(mpushData, 'IOS') || get(mpushData, 'iosContent');
|
|
1283
|
+
let mpushListingData = androidData;
|
|
1284
|
+
if (isEmpty(androidData) || !androidData?.title) {
|
|
1285
|
+
mpushListingData = iosData;
|
|
1286
|
+
};
|
|
1287
|
+
const { title, message, expandableDetails: { style = '', image, carouselData = [], ctas = [] } = {} } = mpushListingData || {};
|
|
1288
|
+
templateData.content = (
|
|
1289
|
+
<CapCard className='mobilepush-container'>
|
|
1290
|
+
<CapHeader className="app-header">
|
|
1291
|
+
<CapRow className="app-header-left">
|
|
1292
|
+
<span className="app-icon">{""}</span>
|
|
1293
|
+
<CapLabel type="label4">{title}</CapLabel>
|
|
1294
|
+
</CapRow>
|
|
1295
|
+
</CapHeader>
|
|
1296
|
+
<CapLabel className="mobilepush-message" type="label1">{message}</CapLabel>
|
|
1297
|
+
{style === BIG_PICTURE && (
|
|
1298
|
+
<CapImage src={image} className="mobilepush-image mobilepush-image-padding" />
|
|
1299
|
+
)}
|
|
1300
|
+
{(style === MANUAL_CAROUSEL || style === AUTO_CAROUSEL || style === FILMSTRIP_CAROUSEL) && (
|
|
1301
|
+
<CapCarousel className="scroll-container">
|
|
1302
|
+
{carouselData.map((data, index) => {
|
|
1303
|
+
return (
|
|
1304
|
+
<CapCard
|
|
1305
|
+
key={`carousel-${index + 1}`}
|
|
1306
|
+
className="whatsapp-carousel-container"
|
|
1307
|
+
role="group"
|
|
1308
|
+
>
|
|
1309
|
+
<CapCard className="whatsapp-carousel-card">
|
|
1310
|
+
{data?.mediaType === IMAGE.toLowerCase() && (
|
|
1311
|
+
<CapImage
|
|
1312
|
+
src={data?.imageUrl ? data?.imageUrl : whatsappImageEmptyPreview}
|
|
1313
|
+
className="whatsapp-image"
|
|
1314
|
+
/>
|
|
1315
|
+
)}
|
|
1316
|
+
{data?.mediaType === VIDEO.toLowerCase() && (
|
|
1317
|
+
<CapCard className="video-preview">
|
|
1318
|
+
<CapImage
|
|
1319
|
+
src={data?.videoPreviewUrl ? data?.videoPreviewUrl : data?.videoPreviewImg ? data?.videoPreviewImg : whatsappVideoEmptyPreview}
|
|
1320
|
+
className="whatsapp-image"
|
|
1321
|
+
/>
|
|
1322
|
+
<CapCard className="icon-position">
|
|
1323
|
+
<CapImage
|
|
1324
|
+
className="video-icon"
|
|
1325
|
+
src={videoPlay}
|
|
1326
|
+
/>
|
|
1327
|
+
</CapCard>
|
|
1328
|
+
</CapCard>
|
|
1329
|
+
)}
|
|
1330
|
+
{
|
|
1331
|
+
data?.mediaType === GIF.toLowerCase() && (
|
|
1332
|
+
<CapCard className="image-preview">
|
|
1333
|
+
<CapImage
|
|
1334
|
+
src={data?.imageUrl ? data?.imageUrl : whatsappImageEmptyPreview}
|
|
1335
|
+
className="whatsapp-image"
|
|
1336
|
+
/>
|
|
1337
|
+
<CapCard className="icon-position">
|
|
1338
|
+
<CapImage
|
|
1339
|
+
className="video-icon"
|
|
1340
|
+
src={data?.imageUrl ? data?.imageUrl : whatsappImageEmptyPreview}
|
|
1341
|
+
/>
|
|
1342
|
+
</CapCard>
|
|
1343
|
+
</CapCard>
|
|
1344
|
+
)
|
|
1345
|
+
}
|
|
1346
|
+
</CapCard>
|
|
1347
|
+
</CapCard>
|
|
1348
|
+
)
|
|
1349
|
+
})}
|
|
1350
|
+
</CapCarousel>
|
|
1351
|
+
)}
|
|
1352
|
+
{ctas.length > 0 && (
|
|
1353
|
+
<CapRow className="actions">
|
|
1354
|
+
{ctas.map((cta) => (
|
|
1355
|
+
<CapLabel
|
|
1356
|
+
className="action"
|
|
1357
|
+
key={`action-${cta?.actionText}`}
|
|
1358
|
+
type="label1"
|
|
1359
|
+
>
|
|
1360
|
+
{cta?.actionText && cta?.actionText.toUpperCase()}
|
|
1361
|
+
</CapLabel>
|
|
1362
|
+
))}
|
|
1363
|
+
</CapRow>
|
|
1364
|
+
)}
|
|
1365
|
+
</CapCard>
|
|
1366
|
+
);
|
|
1367
|
+
templateData.isNewMobilePush = commonUtil.hasNewMobilePushFeatureEnabled();
|
|
1368
|
+
}
|
|
1369
|
+
break;
|
|
1241
1370
|
case INAPP:
|
|
1242
1371
|
templateData.content = template;
|
|
1243
1372
|
break;
|
|
@@ -2053,12 +2182,18 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
2053
2182
|
delete duplicateObj._id;
|
|
2054
2183
|
|
|
2055
2184
|
if (this.state.channel.toLowerCase() === "mobilepush") {
|
|
2185
|
+
const params = {
|
|
2186
|
+
name: this.state.searchText,
|
|
2187
|
+
sortBy: this.state.sortBy,
|
|
2188
|
+
};
|
|
2056
2189
|
duplicateObj.definition.accountId = this.props.Templates.selectedWeChatAccount.id;
|
|
2057
|
-
this.props.
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2190
|
+
this.props.mobilePushNewActions.createTemplate(duplicateObj, (response) => {
|
|
2191
|
+
if (response && (response.templateId || response._id)) {
|
|
2192
|
+
const message = `${this.state.channel} ${this.props.intl.formatMessage(messages.templateDuplicateSuccess)}`;
|
|
2193
|
+
CapNotification.success({key: 'duplicateSuccess', message});
|
|
2194
|
+
this.getAllTemplates({params, resetPage: true});
|
|
2195
|
+
this.props.mobilePushNewActions.clearCreateResponse();
|
|
2196
|
+
}
|
|
2062
2197
|
});
|
|
2063
2198
|
} else if (this.state.channel.toLowerCase() === "inapp") {
|
|
2064
2199
|
duplicateObj.definition.accountId = this.props.Templates.selectedWeChatAccount.id;
|
|
@@ -3399,6 +3534,7 @@ Templates.propTypes = {
|
|
|
3399
3534
|
actions: PropTypes.object.isRequired,
|
|
3400
3535
|
smsActions: PropTypes.object,
|
|
3401
3536
|
mobilepushActions: PropTypes.object,
|
|
3537
|
+
mobilePushNewActions: PropTypes.object,
|
|
3402
3538
|
smsEditActions: PropTypes.object,
|
|
3403
3539
|
ebillActions: PropTypes.object,
|
|
3404
3540
|
emailActions: PropTypes.object,
|
|
@@ -3431,6 +3567,7 @@ const mapStateToProps = createStructuredSelector({
|
|
|
3431
3567
|
TemplatesList: makeSelectTemplatesResponse(),
|
|
3432
3568
|
Create: makeSelectCreateSms(),
|
|
3433
3569
|
CreateMobilePush: makeSelectCreateMobilePush(),
|
|
3570
|
+
MobilePushNew: makeSelectMobilePushNew(),
|
|
3434
3571
|
CreateEbill: makeSelectCreateEbill(),
|
|
3435
3572
|
Edit: makeSelectEdit(),
|
|
3436
3573
|
EmailCreate: makeSelectCreateEmail(),
|
|
@@ -3446,6 +3583,7 @@ function mapDispatchToProps(dispatch) {
|
|
|
3446
3583
|
actions: bindActionCreators(actions, dispatch),
|
|
3447
3584
|
smsActions: bindActionCreators(smsActions, dispatch),
|
|
3448
3585
|
mobilepushActions: bindActionCreators(mobilepushActions, dispatch),
|
|
3586
|
+
mobilePushNewActions: bindActionCreators(mobilePushNewActions, dispatch),
|
|
3449
3587
|
inAppActions: bindActionCreators(inAppActions, dispatch),
|
|
3450
3588
|
smsEditActions: bindActionCreators(smsEditActions, dispatch),
|
|
3451
3589
|
ebillActions: bindActionCreators(ebillActions, dispatch),
|
|
@@ -3469,6 +3607,7 @@ const withSaga = injectSaga({ key: 'templates', saga: v2TemplateSaga, mode: DAEM
|
|
|
3469
3607
|
export default compose(
|
|
3470
3608
|
UserIsAuthenticated,
|
|
3471
3609
|
withSaga,
|
|
3610
|
+
withMobilePushNewSaga,
|
|
3472
3611
|
withReducer,
|
|
3473
3612
|
withConnect,
|
|
3474
3613
|
)(injectIntl(Templates));
|
|
@@ -538,4 +538,12 @@ export default defineMessages({
|
|
|
538
538
|
id: `${scope}.zaloOnlyApprovedTemplates`,
|
|
539
539
|
defaultMessage: 'Only enabled/approved templates are shown here',
|
|
540
540
|
},
|
|
541
|
+
"templateCreateSuccess": {
|
|
542
|
+
id: `${scope}.templateCreateSuccess`,
|
|
543
|
+
defaultMessage: 'Template created successfully',
|
|
544
|
+
},
|
|
545
|
+
"templateUpdateSuccess": {
|
|
546
|
+
id: `${scope}.templateUpdateSuccess`,
|
|
547
|
+
defaultMessage: 'Template updated successfully',
|
|
548
|
+
},
|
|
541
549
|
});
|
|
@@ -9,6 +9,7 @@ import { saveCdnConfigs, removeAllCdnLocalStorageItems } from '../../utils/cdnTr
|
|
|
9
9
|
import { COPY_OF } from '../../containers/App/constants';
|
|
10
10
|
import { ZALO_TEMPLATE_INFO_REQUEST } from '../Zalo/constants';
|
|
11
11
|
import { getTemplateInfoById } from '../Zalo/saga';
|
|
12
|
+
import { watchCreateTemplate } from '../MobilePushNew/sagas';
|
|
12
13
|
// Individual exports for testing
|
|
13
14
|
export function* getAllTemplates(channel, queryParams) {
|
|
14
15
|
try {
|