@capillarytech/creatives-library 7.17.93 → 7.17.95

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/containers/Ebill/index.js +1 -0
  2. package/containers/MobilePush/Edit/index.js +1 -0
  3. package/index.js +6 -0
  4. package/package.json +1 -1
  5. package/routes.js +5 -0
  6. package/v2Components/CapDeviceContent/index.js +311 -0
  7. package/v2Components/CapDeviceContent/index.scss +115 -0
  8. package/v2Components/CapDeviceContent/messages.js +94 -0
  9. package/v2Components/CapDeviceContent/tests/index.test.js +85 -0
  10. package/v2Components/CapImageUpload/index.js +11 -4
  11. package/v2Components/CapImageUpload/messages.js +6 -2
  12. package/v2Components/CapInAppCTA/constants.js +25 -0
  13. package/v2Components/CapInAppCTA/index.js +280 -0
  14. package/v2Components/CapInAppCTA/index.scss +93 -0
  15. package/v2Components/CapInAppCTA/messages.js +85 -0
  16. package/v2Components/FormBuilder/index.js +3 -4
  17. package/v2Components/MobilePushPreviewV2/index.js +78 -23
  18. package/v2Components/TemplatePreview/_templatePreview.scss +449 -0
  19. package/v2Components/TemplatePreview/assets/images/inapp_mobile_android_bottom.svg +11 -0
  20. package/v2Components/TemplatePreview/assets/images/inapp_mobile_android_full.svg +11 -0
  21. package/v2Components/TemplatePreview/assets/images/inapp_mobile_android_modal.svg +11 -0
  22. package/v2Components/TemplatePreview/assets/images/inapp_mobile_android_top.svg +11 -0
  23. package/v2Components/TemplatePreview/assets/images/inapp_mobile_ios_bottom.svg +6 -0
  24. package/v2Components/TemplatePreview/assets/images/inapp_mobile_ios_full.svg +18 -0
  25. package/v2Components/TemplatePreview/assets/images/inapp_mobile_ios_modal.svg +7 -0
  26. package/v2Components/TemplatePreview/assets/images/inapp_mobile_ios_top.svg +13 -0
  27. package/v2Components/TemplatePreview/index.js +660 -375
  28. package/v2Components/TemplatePreview/messages.js +4 -0
  29. package/v2Containers/App/constants.js +1 -0
  30. package/v2Containers/CreativesContainer/SlideBoxContent.js +43 -0
  31. package/v2Containers/CreativesContainer/SlideBoxHeader.js +4 -1
  32. package/v2Containers/CreativesContainer/constants.js +1 -0
  33. package/v2Containers/CreativesContainer/index.js +42 -19
  34. package/v2Containers/CreativesContainer/messages.js +4 -0
  35. package/v2Containers/InApp/actions.js +64 -0
  36. package/v2Containers/InApp/constants.js +125 -0
  37. package/v2Containers/InApp/index.js +762 -0
  38. package/v2Containers/InApp/index.scss +48 -0
  39. package/v2Containers/InApp/messages.js +99 -0
  40. package/v2Containers/InApp/reducer.js +109 -0
  41. package/v2Containers/InApp/sagas.js +143 -0
  42. package/v2Containers/InApp/selectors.js +12 -0
  43. package/v2Containers/InApp/tests/action.test.js +53 -0
  44. package/v2Containers/InApp/tests/index.test.js +142 -0
  45. package/v2Containers/InApp/tests/mockData.js +898 -0
  46. package/v2Containers/InApp/tests/reducer.test.js +177 -0
  47. package/v2Containers/InApp/tests/sagas.test.js +391 -0
  48. package/v2Containers/MobilePush/Edit/index.js +3 -1
  49. package/v2Containers/Templates/_templates.scss +14 -0
  50. package/v2Containers/Templates/index.js +86 -32
  51. package/v2Containers/Templates/messages.js +20 -0
  52. package/v2Containers/TemplatesV2/index.js +2 -1
  53. package/v2Containers/TemplatesV2/messages.js +4 -0
@@ -0,0 +1,762 @@
1
+ import React, { useState, useEffect } from "react";
2
+ import isEmpty from 'lodash/isEmpty';
3
+ import get from 'lodash/get';
4
+ import { bindActionCreators } from "redux";
5
+ import { createStructuredSelector } from "reselect";
6
+ import { injectIntl, FormattedMessage } from "react-intl";
7
+ import CapHeading from "@capillarytech/cap-ui-library/CapHeading";
8
+ import CapSpin from "@capillarytech/cap-ui-library/CapSpin";
9
+ import CapInput from "@capillarytech/cap-ui-library/CapInput";
10
+ import CapRadioGroup from "@capillarytech/cap-ui-library/CapRadioGroup";
11
+ import CapRow from "@capillarytech/cap-ui-library/CapRow";
12
+ import CapColumn from "@capillarytech/cap-ui-library/CapColumn";
13
+ import CapButton from "@capillarytech/cap-ui-library/CapButton";
14
+ import CapTab from "@capillarytech/cap-ui-library/CapTab";
15
+ import CapNotification from "@capillarytech/cap-ui-library/CapNotification";
16
+ import { makeSelectInApp, makeSelectAccount } from "./selectors";
17
+ import {
18
+ isLoadingMetaEntities,
19
+ makeSelectMetaEntities,
20
+ setInjectedTags,
21
+ } from "../Cap/selectors";
22
+ import * as inAppActions from "./actions";
23
+ import './index.scss';
24
+ import messages from "./messages";
25
+ import globalMessages from "../Cap/messages";
26
+ import withCreatives from "../../hoc/withCreatives";
27
+ import TemplatePreview from "../../v2Components/TemplatePreview";
28
+ import { validateTags } from "../../utils/tagValidations";
29
+
30
+ import {
31
+ ANDROID,
32
+ BIG_PICTURE,
33
+ BIG_TEXT,
34
+ DEEP_LINK,
35
+ INAPP_BUTTON_TYPES,
36
+ INAPP_MEDIA_TYPES,
37
+ INAPP_MESSAGE_LAYOUT_TYPES,
38
+ INITIAL_CTA_DATA,
39
+ IOS,
40
+ LAYOUT_RADIO_OPTIONS,
41
+ } from "./constants";
42
+ import { INAPP, SMS } from "../CreativesContainer/constants";
43
+ import { ALL, TAG, EMBEDDED, DEFAULT, FULL, LIBRARY } from "../Whatsapp/constants";
44
+ import CapDeviceContent from "../../v2Components/CapDeviceContent";
45
+ import { getCdnUrl } from "../../utils/cdnTransformation";
46
+ let editContent = {};
47
+
48
+ export const InApp = (props) => {
49
+ const {
50
+ intl,
51
+ actions,
52
+ isFullMode,
53
+ onCreateComplete,
54
+ params,
55
+ templateData = {},
56
+ editData = {},
57
+ accountData = {},
58
+ globalActions,
59
+ location,
60
+ getDefaultTags,
61
+ supportedTags,
62
+ metaEntities,
63
+ injectedTags,
64
+ getFormData,
65
+ selectedOfferDetails,
66
+ } = props || {};
67
+ const { formatMessage } = intl;
68
+ const [titleAndroid, setTitleAndroid] = useState("");
69
+ const [titleIos, setTitleIos] = useState("");
70
+ const [templateMediaTypeAndroid, setTemplateMediaTypeAndroid] = useState(
71
+ INAPP_MEDIA_TYPES.TEXT
72
+ );
73
+ const [templateMediaTypeIos, setTemplateMediaTypeIos] = useState(
74
+ INAPP_MEDIA_TYPES.TEXT
75
+ );
76
+ const [templateName, setTemplateName] = useState("");
77
+ const [templateLayoutType, setTemplateLayoutType] = useState(
78
+ INAPP_MESSAGE_LAYOUT_TYPES.MODAL
79
+ );
80
+ const [addActionLinkAndroid, setAddActionLinkAndroid] = useState(false);
81
+ const [addActionLinkIos, setAddActionLinkIos] = useState(false);
82
+ const [deepLinkValueAndroid, setDeepLinkValueAndroid] = useState('');
83
+ const [deepLinkValueIos, setDeepLinkValueIos] = useState('');
84
+ const [templateMessageAndroid, setTemplateMessageAndroid] = useState("");
85
+ const [templateMessageIos, setTemplateMessageIos] = useState("");
86
+ const [templateMessageErrorAndroid, setTemplateMessageErrorAndroid] = useState(false);
87
+ const [templateMessageErrorIos, setTemplateMessageErrorIos] = useState(false);
88
+ const [accountId, setAccountId] = useState("");
89
+ const [accessToken, setAccessToken] = useState("");
90
+ const [accountName, setAccountName] = useState("");
91
+ const [deepLink, setDeepLink] = useState("");
92
+ const [spin, setSpin] = useState(false);
93
+ const [inAppImageSrcAndroid, setInAppImageSrcAndroid] = useState("");
94
+ const [inAppImageSrcIos, setInAppImageSrcIos] = useState("");
95
+ const [panes, setPanes] = useState(ANDROID);
96
+ //for tag only
97
+ const [tags, updateTags] = useState([]);
98
+ //for edit only
99
+ const [isEditFlow, setEditFlow] = useState(false);
100
+ const [templateDate, setTemplateDate] = useState("");
101
+
102
+ //buttons
103
+ const [ctaDataAndroid, setCtaDataAndroid] = useState(INITIAL_CTA_DATA);
104
+ const [ctaDataIos, setCtaDataIos] = useState(INITIAL_CTA_DATA);
105
+ const [buttonTypeAndroid, setButtonTypeAndroid] = useState(
106
+ INAPP_BUTTON_TYPES.NONE
107
+ );
108
+ const [buttonTypeIos, setButtonTypeIos] = useState(INAPP_BUTTON_TYPES.NONE);
109
+ const isBtnTypeCta = buttonTypeAndroid === INAPP_BUTTON_TYPES.CTA;
110
+
111
+ //gets account details
112
+ useEffect(() => {
113
+ const accountObj = accountData?.selectedWeChatAccount || {};
114
+ const deepLinkObj = accountData?.weCrmAccounts[0]?.configs?.deeplink || {};
115
+ if (!isEmpty(accountObj)) {
116
+ const {
117
+ sourceAccountIdentifier = "",
118
+ configs = {},
119
+ name = "",
120
+ } = accountObj;
121
+ //get deep link keys in an array
122
+ const deepLinkKeys = Object.values(JSON.parse(deepLinkObj));
123
+ const keys = deepLinkKeys.map((link) => ({label: link.name, value: link.link, title: link.link }));
124
+ setDeepLink(keys);
125
+ setAccountId(sourceAccountIdentifier);
126
+ setAccessToken(configs.accessToken || "");
127
+ setAccountName(name);
128
+ }
129
+ }, [accountData?.selectedWeChatAccount, accountData?.weCrmAccounts[0]] );
130
+
131
+ //gets template details
132
+ const paramObj = params || {};
133
+ useEffect(() => {
134
+ const { id } = paramObj;
135
+ if (id) {
136
+ if (isFullMode) {
137
+ setSpin(true);
138
+ actions.getTemplateDetails(id, setSpin);
139
+ }
140
+ }
141
+ //cleanup code
142
+ return () => {
143
+ actions.resetEditTemplate();
144
+ };
145
+ }, [paramObj.id]);
146
+
147
+ useEffect(() => {
148
+ const {
149
+ name = "",
150
+ versions = {},
151
+ createdAt = "",
152
+ } = isFullMode ? editData.templateDetails || {} : templateData || {};
153
+ editContent = get(versions, `base.content`, {});
154
+ if (editContent && !isEmpty(editContent)) {
155
+ setEditFlow(true);
156
+ setTemplateName(name);
157
+ setTemplateDate(createdAt);
158
+ setTemplateLayoutType(editContent?.ANDROID?.bodyType);
159
+ const androidContent = editContent?.ANDROID;
160
+ const {
161
+ title: androidTitle,
162
+ message: androidMessage,
163
+ cta: androidCta,
164
+ expandableDetails: androidExpandableDetails,
165
+ } = androidContent;
166
+ setTitleAndroid(androidTitle);
167
+ setTemplateMessageAndroid(androidMessage);
168
+ setTemplateMediaTypeAndroid(
169
+ androidExpandableDetails?.style === BIG_TEXT
170
+ ? INAPP_MEDIA_TYPES.TEXT
171
+ : INAPP_MEDIA_TYPES.IMAGE
172
+ );
173
+ setInAppImageSrcAndroid(androidExpandableDetails?.image);
174
+ setDeepLinkValueAndroid(androidCta?.actionLink);
175
+ setAddActionLinkAndroid(!isEmpty(androidCta) && true);
176
+ setButtonTypeAndroid(
177
+ androidExpandableDetails?.ctas?.length ? INAPP_BUTTON_TYPES.CTA : INAPP_BUTTON_TYPES.NONE
178
+ );
179
+ if (androidExpandableDetails?.ctas?.length > 0) {
180
+ setCtaDataAndroid(
181
+ androidExpandableDetails?.ctas?.map((cta, index) => {
182
+ const { type, actionText, actionLink = "" } = cta;
183
+ const obj = {
184
+ index,
185
+ text: actionText,
186
+ url: actionLink,
187
+ urlType: type,
188
+ isSaved: true,
189
+ };
190
+ return obj;
191
+ })
192
+ );
193
+ }
194
+ const iosContent = editContent?.IOS;
195
+ const {
196
+ title: iosTitle,
197
+ message: iosMessage,
198
+ cta: iosCta,
199
+ expandableDetails: iosExpandableDetails,
200
+ } = iosContent;
201
+ setTitleIos(iosTitle);
202
+ setTemplateMessageIos(iosMessage);
203
+ setTemplateMediaTypeIos(iosExpandableDetails?.style === BIG_TEXT ? INAPP_MEDIA_TYPES.TEXT : INAPP_MEDIA_TYPES.IMAGE);
204
+ setInAppImageSrcIos(iosExpandableDetails?.image);
205
+ setButtonTypeIos(iosExpandableDetails?.ctas?.length ? INAPP_BUTTON_TYPES.CTA : INAPP_BUTTON_TYPES.NONE);
206
+ setAddActionLinkIos(!isEmpty(iosCta) && true);
207
+ setDeepLinkValueIos(iosCta?.actionLink);
208
+ if (iosExpandableDetails?.ctas?.length > 0) {
209
+ setCtaDataIos(
210
+ iosExpandableDetails?.ctas?.map((cta, index) => {
211
+ const { type, actionText, actionLink = "" } = cta;
212
+ const obj = {
213
+ index,
214
+ text: actionText,
215
+ url: actionLink,
216
+ urlType: type,
217
+ isSaved: true,
218
+ };
219
+ return obj;
220
+ })
221
+ );
222
+ }
223
+ }
224
+ }, [editData.templateDetails || templateData]);
225
+
226
+ // tag Code start from here
227
+ useEffect(() => {
228
+ //fetching tags
229
+ const { type, module } = location.query || {};
230
+ const isEmbedded = type === EMBEDDED;
231
+ const context = isEmbedded ? module : DEFAULT;
232
+ const embedded = isEmbedded ? type : FULL;
233
+ const query = {
234
+ layout: SMS,
235
+ type: TAG,
236
+ context,
237
+ embedded,
238
+ };
239
+ if (getDefaultTags) {
240
+ query.context = getDefaultTags;
241
+ }
242
+ globalActions.fetchSchemaForEntity(query);
243
+ }, []);
244
+
245
+ useEffect(() => {
246
+ let tag = get(metaEntities, `tags.standard`, []);
247
+ const { type, module } = location.query || {};
248
+ if (type === EMBEDDED && module === LIBRARY && !getDefaultTags) {
249
+ tag = supportedTags;
250
+ }
251
+ updateTags(tag);
252
+ }, [metaEntities]);
253
+
254
+ const handleOnTagsContextChange = (data) => {
255
+ const { type } = location.query || {};
256
+ const tempData = (data || '').toLowerCase();
257
+ const isEmbedded = type === EMBEDDED;
258
+ const embedded = isEmbedded ? type : FULL;
259
+ const context = tempData === ALL ? DEFAULT : tempData;
260
+ const query = {
261
+ layout: SMS,
262
+ type: TAG,
263
+ context,
264
+ embedded,
265
+ };
266
+ globalActions.fetchSchemaForEntity(query);
267
+ };
268
+
269
+ const templateDescErrorHandler = (value) => {
270
+ let errorMessage = false;
271
+ const { unsupportedTags, isBraceError } =
272
+ validateTags({
273
+ content: value,
274
+ tagsParam: tags,
275
+ injectedTagsParams: injectedTags,
276
+ location,
277
+ tagModule: getDefaultTags,
278
+ }) || {};
279
+ if (value === '' && INAPP_MEDIA_TYPES.NONE) {
280
+ errorMessage = formatMessage(messages.emptyTemplateDescErrorMessage);
281
+ } else if (unsupportedTags?.length > 0) {
282
+ errorMessage = formatMessage(
283
+ globalMessages.unsupportedTagsValidationError,
284
+ {
285
+ unsupportedTags,
286
+ },
287
+ );
288
+ }
289
+ if (isBraceError) {
290
+ errorMessage = formatMessage(globalMessages.unbalanacedCurlyBraces);
291
+ }
292
+ return errorMessage;
293
+ };
294
+
295
+ const onTagSelect = (data, id) => {
296
+ if (id === 0) {
297
+ const tempTitle = `${panes === ANDROID ? titleAndroid : titleIos}{{${data}}}`;
298
+ if (panes === ANDROID) {
299
+ setTitleAndroid(tempTitle);
300
+ } else {
301
+ setTitleIos(tempTitle);
302
+ }
303
+ } else {
304
+ const tempMsg = `${panes === ANDROID ? templateMessageAndroid : templateMessageIos}{{${data}}}`;
305
+ const error = templateDescErrorHandler(tempMsg);
306
+ if (panes === ANDROID) {
307
+ setTemplateMessageAndroid(tempMsg);
308
+ setTemplateMessageErrorAndroid(error);
309
+ } else {
310
+ setTemplateMessageIos(tempMsg);
311
+ setTemplateMessageErrorIos(error);
312
+ }
313
+ }
314
+ };
315
+
316
+ // tag Code end
317
+
318
+ const onTemplateNameChange = ({ target: { value } }) => {
319
+ setTemplateName(value);
320
+ };
321
+
322
+ const onTemplateLayoutTypeChange = ({ target: { value } }) => {
323
+ setTemplateLayoutType(value);
324
+ };
325
+
326
+ const onCopyTitleAndContent = () => {
327
+ if (panes === ANDROID) {
328
+ setTitleAndroid(titleIos);
329
+ setTemplateMessageAndroid(templateMessageIos);
330
+ } else {
331
+ setTitleIos(titleAndroid);
332
+ setTemplateMessageIos(templateMessageAndroid);
333
+ }
334
+ };
335
+
336
+
337
+ const PANES = [
338
+ {
339
+ content: (
340
+ <CapDeviceContent
341
+ intl={intl}
342
+ location={location}
343
+ injectedTags={injectIntl}
344
+ selectedOfferDetails={selectedOfferDetails}
345
+ panes={panes}
346
+ actions={actions}
347
+ editData={editData}
348
+ isFullMode={isFullMode}
349
+ inAppImageSrc={inAppImageSrcAndroid}
350
+ setInAppImageSrc={setInAppImageSrcAndroid}
351
+ isEditFlow={isEditFlow}
352
+ ctaData={ctaDataAndroid}
353
+ setCtaData={setCtaDataAndroid}
354
+ buttonType={buttonTypeAndroid}
355
+ setButtonType={setButtonTypeAndroid}
356
+ accountId={accountId}
357
+ accessToken={accessToken}
358
+ templateMediaType={templateMediaTypeAndroid}
359
+ setTemplateMediaType={setTemplateMediaTypeAndroid}
360
+ title={titleAndroid}
361
+ setTitle={setTitleAndroid}
362
+ templateMessageError={templateMessageErrorAndroid}
363
+ templateMessage={templateMessageAndroid}
364
+ setTemplateMessage={setTemplateMessageAndroid}
365
+ setTemplateMessageError={setTemplateMessageErrorAndroid}
366
+ addActionLink={addActionLinkAndroid}
367
+ setAddActionLink={setAddActionLinkAndroid}
368
+ deepLink={deepLink}
369
+ deepLinkValue={deepLinkValueAndroid}
370
+ setDeepLinkValue={setDeepLinkValueAndroid}
371
+ onCopyTitleAndContent={onCopyTitleAndContent}
372
+ tags={tags}
373
+ onTagSelect={onTagSelect}
374
+ handleOnTagsContextChange={handleOnTagsContextChange}
375
+ templateDescErrorHandler={templateDescErrorHandler}
376
+ />
377
+ ),
378
+ tab: <FormattedMessage {...messages.Android} />,
379
+ key: ANDROID,
380
+ },
381
+ {
382
+ content: (
383
+ <CapDeviceContent
384
+ intl={intl}
385
+ location={location}
386
+ injectedTags={injectIntl}
387
+ selectedOfferDetails={selectedOfferDetails}
388
+ panes={panes}
389
+ actions={actions}
390
+ editData={editData}
391
+ isFullMode={isFullMode}
392
+ inAppImageSrc={inAppImageSrcIos}
393
+ setInAppImageSrc={setInAppImageSrcIos}
394
+ isEditFlow={isEditFlow}
395
+ ctaData={ctaDataIos}
396
+ setCtaData={setCtaDataIos}
397
+ buttonType={buttonTypeIos}
398
+ setButtonType={setButtonTypeIos}
399
+ accountId={accountId}
400
+ accessToken={accessToken}
401
+ templateMediaType={templateMediaTypeIos}
402
+ setTemplateMediaType={setTemplateMediaTypeIos}
403
+ title={titleIos}
404
+ setTitle={setTitleIos}
405
+ templateMessageError={templateMessageErrorIos}
406
+ templateMessage={templateMessageIos}
407
+ setTemplateMessage={setTemplateMessageIos}
408
+ setTemplateMessageError={setTemplateMessageErrorIos}
409
+ addActionLink={addActionLinkIos}
410
+ setAddActionLink={setAddActionLinkIos}
411
+ deepLink={deepLink}
412
+ deepLinkValue={deepLinkValueIos}
413
+ setDeepLinkValue={setDeepLinkValueIos}
414
+ onCopyTitleAndContent={onCopyTitleAndContent}
415
+ tags={tags}
416
+ onTagSelect={onTagSelect}
417
+ handleOnTagsContextChange={handleOnTagsContextChange}
418
+ />
419
+ ),
420
+ tab: <FormattedMessage {...messages.Ios} />,
421
+ key: IOS,
422
+ },
423
+ ];
424
+
425
+ const createModeContent = (
426
+ <CapRow>
427
+ {/* template name */}
428
+ <CapRow>
429
+ <CapHeading type="h4">
430
+ <FormattedMessage {...messages.creativeName} />
431
+ </CapHeading>
432
+ <CapInput
433
+ id="inapp-template-name-input"
434
+ className="inapp-template-name-input"
435
+ onChange={onTemplateNameChange}
436
+ placeholder={formatMessage(globalMessages.templateNamePlaceholder)}
437
+ value={templateName}
438
+ size="default"
439
+ />
440
+ </CapRow>
441
+ {/* Creative layout type*/}
442
+ <CapRow className="inapp-creative-layout">
443
+ <CapHeading type="h4">
444
+ <FormattedMessage {...messages.creativeLayout} />
445
+ </CapHeading>
446
+ <CapHeading type="h6" className="inapp-creative-layout-desc">
447
+ <FormattedMessage {...messages.creativeLayoutDesc} />
448
+ </CapHeading>
449
+ </CapRow>
450
+ <CapRadioGroup
451
+ id="inapp-layout-radio"
452
+ options={LAYOUT_RADIO_OPTIONS}
453
+ value={templateLayoutType}
454
+ onChange={onTemplateLayoutTypeChange}
455
+ className="inapp-layout-radio"
456
+ />
457
+ </CapRow>
458
+ );
459
+ //create methods end
460
+
461
+ //used by create and edit
462
+ const getPreviewSection = () => {
463
+ const templateTitle = panes === ANDROID ? titleAndroid : titleIos;
464
+ const templateMsg = panes === ANDROID ? templateMessageAndroid : templateMessageIos;
465
+ const mediaPreview = {};
466
+ let ctaData = {};
467
+ if (panes === ANDROID) {
468
+ ctaData = ctaDataAndroid;
469
+ switch (templateMediaTypeAndroid) {
470
+ case INAPP_MEDIA_TYPES.IMAGE:
471
+ mediaPreview.inAppImageSrcAndroid = inAppImageSrcAndroid;
472
+ break;
473
+ default:
474
+ break;
475
+ }
476
+ } else {
477
+ ctaData = ctaDataIos;
478
+ switch (templateMediaTypeIos) {
479
+ case INAPP_MEDIA_TYPES.IMAGE:
480
+ mediaPreview.inAppImageSrcIos = inAppImageSrcIos;
481
+ break;
482
+ default:
483
+ break;
484
+ }
485
+ }
486
+ return (
487
+ <TemplatePreview
488
+ channel={INAPP}
489
+ content={{
490
+ inAppPreviewContent: {
491
+ mediaPreview,
492
+ templateTitle,
493
+ templateMsg,
494
+ ...(isBtnTypeCta && {
495
+ ctaData,
496
+ }),
497
+ },
498
+ }}
499
+ inAppAccountName={accountName}
500
+ templateLayoutType={templateLayoutType}
501
+ device={panes}
502
+ />
503
+ );
504
+ };
505
+
506
+ const isDisableDone = () => {
507
+ //if template name is not entered
508
+ if (templateName.trim() === '') {
509
+ return true;
510
+ }
511
+ //if template message is not entered
512
+ //for android
513
+ if (panes === ANDROID && (templateMessageAndroid.trim() === '' || templateMessageErrorAndroid)) {
514
+ return true;
515
+ }
516
+ if (panes === IOS && (templateMessageIos.trim() === '' || templateMessageErrorIos)) {
517
+ return true;
518
+ }//for ios
519
+ //if media type is image and the mediaType file is not uploaded
520
+ if (panes === ANDROID && !(templateMediaTypeAndroid === INAPP_MEDIA_TYPES.TEXT) && inAppImageSrcAndroid === '') {
521
+ return true;
522
+ }
523
+ if (panes === IOS && !(templateMediaTypeIos === INAPP_MEDIA_TYPES.TEXT) && inAppImageSrcIos === '') {
524
+ return true;
525
+ }
526
+ //cta
527
+ if (isBtnTypeCta) {
528
+ if (panes === ANDROID && ctaDataAndroid[0]?.isSaved) {
529
+ //if button type is cta and 1st button is saved
530
+ return false;
531
+ }
532
+ if (panes === IOS && ctaDataIos[0]?.isSaved) {
533
+ //if button type is cta and 1st button is saved
534
+ return false;
535
+ }
536
+ //if button type is cta and there are no buttons saved
537
+ return true;
538
+ }
539
+ return false;
540
+ };
541
+
542
+ const getCtaPayload = (type) =>
543
+ (type === ANDROID ? ctaDataAndroid : ctaDataIos).map((cta) => {
544
+ const { text, urlType, url } = cta;
545
+ return {
546
+ type: urlType,
547
+ actionText: text,
548
+ actionLink: url,
549
+ };
550
+ });
551
+
552
+ const createPayload = () => {
553
+ let androidMediaParams = {};
554
+ let iosMediaParams = {};
555
+ const commonDevicePayload = {
556
+ luid: "{{luid}}",
557
+ cuid: "{{cuid}}",
558
+ communicationId: "{{communicationId}}",
559
+ };
560
+ switch (templateMediaTypeAndroid) {
561
+ case INAPP_MEDIA_TYPES.IMAGE:
562
+ androidMediaParams = {
563
+ image: getCdnUrl({url: inAppImageSrcAndroid, channelName: INAPP }),
564
+ style: BIG_PICTURE,
565
+ };
566
+ break;
567
+ default:
568
+ break;
569
+ }
570
+ switch (templateMediaTypeIos) {
571
+ case INAPP_MEDIA_TYPES.IMAGE:
572
+ iosMediaParams = {
573
+ image: getCdnUrl({url: inAppImageSrcIos, channelName: INAPP }),
574
+ style: BIG_PICTURE,
575
+ };
576
+ break;
577
+ default:
578
+ break;
579
+ }
580
+ const accountObj = accountData?.selectedWeChatAccount || {};
581
+ const {
582
+ sourceAccountIdentifier = "",
583
+ id,
584
+ } = accountObj;
585
+ const data = {
586
+ name: templateName,
587
+ versions: {
588
+ base: {
589
+ content: {
590
+ ANDROID: {
591
+ ...commonDevicePayload,
592
+ title: titleAndroid,
593
+ message: templateMessageAndroid,
594
+ bodyType: templateLayoutType,
595
+ expandableDetails: {
596
+ style: BIG_TEXT,
597
+ message: templateMessageAndroid,
598
+ ...androidMediaParams,
599
+ ...(isBtnTypeCta && {
600
+ ctas: getCtaPayload(ANDROID),
601
+ }),
602
+ },
603
+ custom: [],
604
+ cta: deepLinkValueAndroid ? {type: DEEP_LINK, actionLink: deepLinkValueAndroid} : {},
605
+ },
606
+ IOS: {
607
+ ...commonDevicePayload,
608
+ title: titleIos,
609
+ message: templateMessageIos,
610
+ bodyType: templateLayoutType,
611
+ expandableDetails: {
612
+ style: BIG_TEXT,
613
+ message: templateMessageIos,
614
+ ...iosMediaParams,
615
+ ...(isBtnTypeCta && {
616
+ ctas: getCtaPayload(IOS),
617
+ }),
618
+ },
619
+ custom: [],
620
+ cta: deepLinkValueIos ? {type: DEEP_LINK, actionLink: deepLinkValueIos} : {},
621
+ },
622
+ },
623
+ },
624
+ },
625
+ type: INAPP,
626
+ definition: {
627
+ accountId: id,
628
+ licenseCode: sourceAccountIdentifier,
629
+ mode: "CREATE",
630
+ },
631
+ };
632
+ return data;
633
+ };
634
+
635
+ const actionCallback = ({ errorMessage }) => {
636
+ if (!errorMessage) {
637
+ CapNotification.success({
638
+ message: isEditFlow ? formatMessage(messages.inAppEditNotification, {
639
+ name: templateName,
640
+ }) : formatMessage(messages.inAppCreateNotification, {
641
+ name: templateName,
642
+ }),
643
+ });
644
+ actions.clearCreateResponse();
645
+ } else {
646
+ CapNotification.error({
647
+ message: JSON.stringify(errorMessage),
648
+ });
649
+ }
650
+ };
651
+
652
+ const onCreateInApp = () => {
653
+ setSpin(true);
654
+ actions.createInAppTemplate(createPayload(), (resp, errorMessage) => {
655
+ actionCallback({ resp, errorMessage });
656
+ if (!errorMessage) {
657
+ onCreateComplete();
658
+ } else {
659
+ setSpin(false);
660
+ }
661
+ });
662
+ };
663
+
664
+ const onEditInApp = () => {
665
+ setSpin(true);
666
+ actions.editTemplate(
667
+ {
668
+ ...createPayload(),
669
+ _id: params.id,
670
+ },
671
+ (resp, errorMessage) => {
672
+ actionCallback({ resp, errorMessage });
673
+ if (!errorMessage) {
674
+ onCreateComplete();
675
+ } else {
676
+ setSpin(false);
677
+ }
678
+ },
679
+ );
680
+ };
681
+
682
+
683
+ const onDoneCallback = () => {
684
+ if (isFullMode) {
685
+ if (isEditFlow) {
686
+ return onEditInApp;
687
+ }
688
+ return onCreateInApp;
689
+ }
690
+ return () =>
691
+ getFormData({
692
+ value: createPayload(),
693
+ _id: params && params.id,
694
+ validity: true,
695
+ type: INAPP,
696
+ });
697
+ };
698
+
699
+ return (
700
+ <CapSpin spinning={spin}>
701
+ <CapRow className="cap-inapp-creatives">
702
+ <CapColumn span={14}>
703
+ {isFullMode && createModeContent}
704
+ {/* device tab */}
705
+ <CapTab
706
+ panes={PANES}
707
+ onChange={(value) => {
708
+ setPanes(value);
709
+ }}
710
+ activeKey={panes}
711
+ defaultActiveKey={panes}
712
+ className="inapp-template-device-tab"
713
+ />
714
+ <div className="inapp-scroll-div" />
715
+ </CapColumn>
716
+ <CapColumn span={10} className="inapp-preview-container">
717
+ {getPreviewSection()}
718
+ </CapColumn>
719
+ </CapRow>
720
+ <div className="inapp-footer">
721
+ {
722
+ <>
723
+ <CapButton
724
+ onClick={onDoneCallback()}
725
+ disabled={isDisableDone()}
726
+ className="inapp-create-btn"
727
+ >
728
+ {isEditFlow ? (
729
+ isFullMode ? (
730
+ <FormattedMessage {...messages.update} />
731
+ ) : (
732
+ <FormattedMessage {...globalMessages.done} />
733
+ )
734
+ ) : (
735
+ <FormattedMessage {...messages.create} />
736
+ )}
737
+ </CapButton>
738
+ </>
739
+ }
740
+ </div>
741
+ </CapSpin>
742
+ );
743
+ };
744
+
745
+ const mapStateToProps = createStructuredSelector({
746
+ editData: makeSelectInApp(),
747
+ accountData: makeSelectAccount(),
748
+ metaEntities: makeSelectMetaEntities(),
749
+ loadingTags: isLoadingMetaEntities(),
750
+ injectedTags: setInjectedTags(),
751
+ });
752
+
753
+ const mapDispatchToProps = (dispatch) => ({
754
+ actions: bindActionCreators(inAppActions, dispatch),
755
+ });
756
+
757
+ export default withCreatives({
758
+ WrappedComponent: injectIntl(InApp),
759
+ mapStateToProps,
760
+ mapDispatchToProps,
761
+ userAuth: true,
762
+ });