@capillarytech/creatives-library 7.17.97-alpha.0 → 7.17.98

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@capillarytech/creatives-library",
3
3
  "author": "meharaj",
4
- "version": "7.17.97-alpha.0",
4
+ "version": "7.17.98",
5
5
  "description": "Capillary creatives ui",
6
6
  "main": "./index.js",
7
7
  "module": "./index.es.js",
@@ -65,6 +65,9 @@ const CapDeviceContent = (props) => {
65
65
  tags,
66
66
  onTagSelect,
67
67
  handleOnTagsContextChange,
68
+ templateDescErrorHandler,
69
+ templateTitleError,
70
+ setTemplateTitleError,
68
71
  } = props || {};
69
72
  const { TextArea } = CapInput;
70
73
  const { formatMessage } = intl;
@@ -73,7 +76,7 @@ const CapDeviceContent = (props) => {
73
76
  const isMediaTypeImage = INAPP_MEDIA_TYPES.IMAGE === templateMediaType;
74
77
  const isBtnTypeCta = buttonType === INAPP_BUTTON_TYPES.CTA;
75
78
  const onTemplateMessageChange = ({ target: { value } }) => {
76
- let error = '';
79
+ let error = templateDescErrorHandler(value);
77
80
  if (value === '') {
78
81
  error = formatMessage(messages.emptyTemplateMessageErrorMessage);
79
82
  }
@@ -118,7 +121,12 @@ const CapDeviceContent = (props) => {
118
121
  };
119
122
 
120
123
  const onTitleChange = ({ target: { value } }) => {
124
+ let error = templateDescErrorHandler(value);
125
+ if (value === '') {
126
+ error = formatMessage(messages.emptyTemplateMessageErrorMessage);
127
+ }
121
128
  setTitle(value);
129
+ setTemplateTitleError(error);
122
130
  };
123
131
 
124
132
  const onTemplateMediaTypeChange = ({ target: { value } }) => {
@@ -175,6 +183,11 @@ const CapDeviceContent = (props) => {
175
183
  value={title}
176
184
  size="default"
177
185
  isRequired
186
+ errorMessage={templateTitleError && (
187
+ <CapError className="inapp-template-message-error">
188
+ {templateTitleError}
189
+ </CapError>
190
+ )}
178
191
  />
179
192
  </CapRow>
180
193
  <CapRow className="creatives-inapp-media">
@@ -48,7 +48,7 @@
48
48
  }
49
49
  .cap-custom-image-upload {
50
50
  .dragger-button.re-upload {
51
- top: 12rem;
51
+ top: 13rem;
52
52
  position: absolute;
53
53
  right: $CAP_SPACE_20;
54
54
  color: $FONT_COLOR_05;
@@ -24,7 +24,7 @@ const renderComponent = (props) =>
24
24
 
25
25
  describe('Test CapDeviceContent', () => {
26
26
  it('test case for CapDeviceContent component Android pane', async () => {
27
- renderComponent(deviceContentProps);
27
+ renderComponent({...deviceContentProps, templateDescErrorHandler: jest.fn()});
28
28
  const msgBox = screen.getAllByPlaceholderText(/Please input in-app notification message content/i);
29
29
  fireEvent.change(msgBox[0], 'val');
30
30
  const copyLink = screen.getByRole('link', {
@@ -39,11 +39,13 @@ describe('Test CapDeviceContent', () => {
39
39
  panes: "iOS",
40
40
  buttonType: "CTA",
41
41
  setTemplateMediaType: jest.fn(),
42
+ setTemplateTitleError: jest.fn(),
42
43
  setButtonType: jest.fn(),
43
44
  setCtaData: jest.fn(),
44
45
  setTemplateMessage: jest.fn(),
45
46
  setTemplateMessageError: jest.fn(),
46
47
  setTitle: jest.fn(),
48
+ templateDescErrorHandler: jest.fn(),
47
49
  templateMediType: "IMAGE",
48
50
  addActionLink: true,
49
51
  ctaData: [
@@ -3,7 +3,7 @@ import { FormattedMessage } from 'react-intl';
3
3
  import messages from './messages';
4
4
 
5
5
  export const DEEP_LINK = 'DEEP_LINK';
6
- export const EXTERNAL_LINK = 'EXTERNAL_LINK';
6
+ export const EXTERNAL_URL = 'EXTERNAL_URL';
7
7
  export const WEBSITE = 'WEBSITE';
8
8
 
9
9
  export const CTA_OPTIONS = [
@@ -14,8 +14,8 @@ export const CTA_OPTIONS = [
14
14
  tooltipLabel: <FormattedMessage {...messages.ctaOptionDisabledTooltipDeepLink} />,
15
15
  },
16
16
  {
17
- key: EXTERNAL_LINK,
18
- value: EXTERNAL_LINK,
17
+ key: EXTERNAL_URL,
18
+ value: EXTERNAL_URL,
19
19
  label: <FormattedMessage {...messages.ctaLinkTypeExternal} />,
20
20
  tooltipLabel: <FormattedMessage {...messages.ctaOptionDisabledTooltipExternalLink} />,
21
21
  },
@@ -25,7 +25,7 @@ import {
25
25
  import {
26
26
  BTN_MAX_LENGTH,
27
27
  DEEP_LINK,
28
- EXTERNAL_LINK,
28
+ EXTERNAL_URL,
29
29
  CTA_OPTIONS,
30
30
  URL_MAX_LENGTH,
31
31
  } from "./constants";
@@ -108,7 +108,7 @@ export const CapInAppCTA = (props) => {
108
108
  return true;
109
109
  } else if (urlType === DEEP_LINK && (ctaDeepLinkValue === "" || urlError)) {
110
110
  return true;
111
- } else if (urlType === EXTERNAL_LINK && (url === "" || urlError)) {
111
+ } else if (urlType === EXTERNAL_URL && (url === "" || urlError)) {
112
112
  return true;
113
113
  }
114
114
  };
@@ -223,7 +223,7 @@ export const CapInAppCTA = (props) => {
223
223
  </>
224
224
 
225
225
  )}
226
- {urlType === EXTERNAL_LINK && (
226
+ {urlType === EXTERNAL_URL && (
227
227
  <>
228
228
  <CapHeading type="h4">
229
229
  {formatMessage(messages.urlExternalLink)}
@@ -929,7 +929,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
929
929
  }
930
930
  // Check if template subject present in form data from Loyalty, DVS, Timeline
931
931
  if (index === 'template-subject' && type.toLowerCase() === 'embedded' && (currentModule.toLowerCase() === 'loyalty' || currentModule.toLowerCase() === 'dvs' || currentModule.toLowerCase() === 'timeline' || currentModule.toLowerCase() === 'library')) {
932
- if ((data && data.trim() === '') || !data) {
932
+ if (data && data.trim() === '') {
933
933
  errorData[index] = true;
934
934
  isValid = false;
935
935
  } else {
@@ -14,6 +14,7 @@ import '../PreviewSideBar/_previewsidebar.scss';
14
14
  import { MOBILE_PUSH } from '../../v2Containers/CreativesContainer/constants';
15
15
  import { INAPP } from '../../v2Containers/App/constants';
16
16
  import { ANDROID, IOS } from '../../v2Containers/InApp/constants';
17
+ import { getCtaObject } from '../../v2Containers/InApp/utils';
17
18
 
18
19
  class MobilePushPreviewV2 extends React.Component { // eslint-disable-line react/prefer-stateless-function
19
20
  constructor(props) {
@@ -47,35 +48,13 @@ class MobilePushPreviewV2 extends React.Component { // eslint-disable-line react
47
48
  templateTitle: androidContent?.title,
48
49
  templateMsg: androidContent?.message,
49
50
  mediaPreview: { inAppImageSrcAndroid: androidContent?.expandableDetails?.image },
50
- ctaData: androidContent?.expandableDetails?.buttons?.map((cta) => {
51
- const { index, type, text, url = "", label } = cta;
52
- const ctaObject = {
53
- index,
54
- text,
55
- url,
56
- urlType: type,
57
- isSaved: true,
58
- label,
59
- };
60
- return ctaObject;
61
- }),
51
+ ctaData: getCtaObject(androidContent?.expandableDetails?.ctas),
62
52
  };
63
53
  const iosPreviewContent = {
64
54
  templateTitle: iosContent?.title,
65
55
  templateMsg: iosContent?.message,
66
56
  mediaPreview: { inAppImageSrcIos: iosContent?.expandableDetails?.image },
67
- ctaData: iosContent?.expandableDetails?.buttons?.map((cta) => {
68
- const { index, type, text, url = "", label } = cta;
69
- const ctaObject = {
70
- index,
71
- text,
72
- url,
73
- urlType: type,
74
- isSaved: true,
75
- label,
76
- };
77
- return ctaObject;
78
- }),
57
+ ctaData: getCtaObject(iosContent?.expandableDetails?.ctas),
79
58
  };
80
59
  content = {
81
60
  inAppPreviewContent: device === ANDROID.toLowerCase() ? androidPreviewContent : iosPreviewContent,
@@ -38,7 +38,7 @@
38
38
  }
39
39
 
40
40
  .inapp-content-POPUP-ANDROID {
41
- margin-top: $CAP_SPACE_12;
41
+ margin-top: $CAP_SPACE_08;
42
42
  margin-right: $CAP_SPACE_08;
43
43
  margin-left: $CAP_SPACE_08;
44
44
  width: 178px;
@@ -81,7 +81,7 @@
81
81
  left: 26%;
82
82
  bottom: -21px;
83
83
  text-align: center;
84
- top: 22%;
84
+ top: 22px;
85
85
  }
86
86
 
87
87
  .inapp-image-HEADER-ANDROID {
@@ -221,7 +221,7 @@
221
221
 
222
222
  .inapp-content-FULLSCREEN-ANDROID {
223
223
  width: 186px;
224
- height: 144px;
224
+ max-height: 144px;
225
225
  text-align: left;
226
226
  margin-top: $CAP_SPACE_04;
227
227
  text-overflow: ellipsis;
@@ -440,7 +440,7 @@
440
440
 
441
441
  .inapp-content-FULLSCREEN-iOS {
442
442
  width: 186px;
443
- height: 144px;
443
+ max-height: 144px;
444
444
  text-align: left;
445
445
  margin-top: $CAP_SPACE_04;
446
446
  text-overflow: ellipsis;
@@ -808,6 +808,9 @@ export function SlideBoxContent(props) {
808
808
  query,
809
809
  search: '',
810
810
  }}
811
+ getFormData={getFormData}
812
+ isGetFormData={isGetFormData}
813
+ templateData={templateData}
811
814
  />
812
815
  )}
813
816
 
@@ -291,12 +291,14 @@ export class Creatives extends React.Component {
291
291
  type: channel,
292
292
  name: templateData.messageSubject,
293
293
  versions: {
294
- content: {
295
- ANDROID: templateData.androidContent,
296
- IOS: templateData.iosContent,
294
+ base: {
295
+ content: {
296
+ ANDROID: templateData?.androidContent,
297
+ IOS: templateData?.iosContent,
298
+ },
297
299
  },
298
300
  },
299
- definition: {accountId: templateData.accountId, mode: mode.toLowerCase()},
301
+ definition: {accountId: templateData?.accountId, mode: mode?.toLowerCase()},
300
302
  };
301
303
  break;
302
304
  }
@@ -2069,13 +2069,7 @@ export class Email extends React.Component { // eslint-disable-line react/prefer
2069
2069
  formData[0].selectedLanguages = [];
2070
2070
  let tabKey;
2071
2071
  if ((this.props.location.query.isLanguageSupport === undefined || this.props.location.query.isLanguageSupport === 'false')) {
2072
- const templateSubject = formData?.['template-subject'];
2073
- const baseSubject = data?.base?.subject;
2074
- if (templateSubject === '') {
2075
- formData['template-subject'] = '';
2076
- } else if (!templateSubject && baseSubject) {
2077
- formData['template-subject'] = baseSubject;
2078
- }
2072
+ formData['template-subject'] = data.base.subject ? data.base.subject : '';
2079
2073
  const baseLanguage = this.props.currentOrgDetails.basic_details.base_language;
2080
2074
  let languageIndex = _.findIndex(this.supportedLanguages, {iso_code: baseLanguage});
2081
2075
 
@@ -1,5 +1,15 @@
1
1
  import React from "react";
2
2
  import { FormattedMessage } from "react-intl";
3
+ import {
4
+ CAP_ORANGE,
5
+ CAP_PURPLE02,
6
+ CAP_PURPLE03,
7
+ CAP_ORANGE01,
8
+ CAP_GREEN01,
9
+ CAP_GREEN02,
10
+ CAP_PALE_GREY,
11
+ FONT_COLOR_05,
12
+ } from '@capillarytech/cap-ui-library/styled/variables';
3
13
  import CapHeading from "@capillarytech/cap-ui-library/CapHeading";
4
14
  import CapLabel from "@capillarytech/cap-ui-library/CapLabel";
5
15
  import { WEBSITE } from "../../v2Components/CapInAppCTA/constants";
@@ -123,3 +133,28 @@ export const BUTTON_RADIO_OPTIONS = [
123
133
  ),
124
134
  },
125
135
  ];
136
+
137
+ export const INAPP_LAYOUT_DETAILS = {
138
+ POPUP: {
139
+ tagColor: CAP_ORANGE01,
140
+ tagTextColor: CAP_ORANGE,
141
+ text: <FormattedMessage {...messages.popup} />,
142
+ },
143
+ HEADER: {
144
+ tagColor: CAP_PURPLE03,
145
+ tagTextColor: CAP_PURPLE02,
146
+ text: <FormattedMessage {...messages.header} />,
147
+ },
148
+ FOOTER: {
149
+ tagColor: CAP_PALE_GREY,
150
+ tagTextColor: FONT_COLOR_05,
151
+ text: <FormattedMessage {...messages.footer} />,
152
+ },
153
+ FULLSCREEN: {
154
+ tagColor: CAP_GREEN02,
155
+ tagTextColor: CAP_GREEN01,
156
+ text: <FormattedMessage {...messages.layoutFullScreen} />,
157
+ },
158
+ };
159
+
160
+ export const DEVICE_SUPPORTED = '1';
@@ -32,6 +32,7 @@ import {
32
32
  BIG_PICTURE,
33
33
  BIG_TEXT,
34
34
  DEEP_LINK,
35
+ DEVICE_SUPPORTED,
35
36
  INAPP_BUTTON_TYPES,
36
37
  INAPP_MEDIA_TYPES,
37
38
  INAPP_MESSAGE_LAYOUT_TYPES,
@@ -43,6 +44,7 @@ import { INAPP, SMS } from "../CreativesContainer/constants";
43
44
  import { ALL, TAG, EMBEDDED, DEFAULT, FULL, LIBRARY } from "../Whatsapp/constants";
44
45
  import CapDeviceContent from "../../v2Components/CapDeviceContent";
45
46
  import { getCdnUrl } from "../../utils/cdnTransformation";
47
+ import { getCtaObject } from "./utils";
46
48
  let editContent = {};
47
49
 
48
50
  export const InApp = (props) => {
@@ -82,6 +84,8 @@ export const InApp = (props) => {
82
84
  const [templateMessageIos, setTemplateMessageIos] = useState("");
83
85
  const [templateMessageErrorAndroid, setTemplateMessageErrorAndroid] = useState(false);
84
86
  const [templateMessageErrorIos, setTemplateMessageErrorIos] = useState(false);
87
+ const [templateTitleErrorAndroid, setTemplateTitleErrorAndroid] = useState(false);
88
+ const [templateTitleErrorIos, setTemplateTitleErrorIos] = useState(false);
85
89
  const [accountId, setAccountId] = useState("");
86
90
  const [accessToken, setAccessToken] = useState("");
87
91
  const [accountName, setAccountName] = useState("");
@@ -116,9 +120,12 @@ export const InApp = (props) => {
116
120
  configs = {},
117
121
  name = "",
118
122
  } = accountObj;
123
+ const isAndroidSupported = configs?.android === DEVICE_SUPPORTED;
124
+ // DEVICE_SUPPORTED is '1', which indicates if the particular account is supported, and '0' if the devive is not supported
119
125
  //get deep link keys in an array
120
126
  const deepLinkKeys = Object.values(JSON.parse(deepLinkObj));
121
127
  const keys = deepLinkKeys.map((link) => ({label: link.name, value: link.link, title: link.link }));
128
+ setPanes(isAndroidSupported ? ANDROID : IOS);
122
129
  setDeepLink(keys);
123
130
  setAccountId(sourceAccountIdentifier);
124
131
  setAccessToken(configs.accessToken || "");
@@ -147,7 +154,7 @@ export const InApp = (props) => {
147
154
  name = "",
148
155
  versions = {},
149
156
  createdAt = "",
150
- } = isFullMode ? editData.templateDetails || {} : templateData || {};
157
+ } = isFullMode ? editData?.templateDetails || {} : templateData || {};
151
158
  editContent = get(versions, `base.content`, {});
152
159
  if (editContent && !isEmpty(editContent)) {
153
160
  setEditFlow(true);
@@ -155,68 +162,60 @@ export const InApp = (props) => {
155
162
  setTemplateDate(createdAt);
156
163
  setTemplateLayoutType(editContent?.ANDROID?.bodyType);
157
164
  const androidContent = editContent?.ANDROID;
158
- const {
159
- title: androidTitle,
160
- message: androidMessage,
161
- cta: androidCta,
162
- expandableDetails: androidExpandableDetails,
163
- } = androidContent;
164
- setTitleAndroid(androidTitle);
165
- setTemplateMessageAndroid(androidMessage);
166
- setTemplateMediaType(
167
- androidExpandableDetails?.style === BIG_TEXT
168
- ? INAPP_MEDIA_TYPES.TEXT
169
- : INAPP_MEDIA_TYPES.IMAGE
170
- );
171
- setInAppImageSrcAndroid(androidExpandableDetails?.image);
172
- setDeepLinkValueAndroid(androidCta?.actionLink);
173
- setAddActionLinkAndroid(!isEmpty(androidCta) && true);
174
- setButtonTypeAndroid(
175
- androidExpandableDetails?.ctas?.length ? INAPP_BUTTON_TYPES.CTA : INAPP_BUTTON_TYPES.NONE
176
- );
177
- if (androidExpandableDetails?.ctas?.length > 0) {
178
- setCtaDataAndroid(
179
- androidExpandableDetails?.ctas?.map((cta, index) => {
180
- const { type, actionText, actionLink = "" } = cta;
181
- const obj = {
182
- index,
183
- text: actionText,
184
- url: actionLink,
185
- urlType: type,
186
- isSaved: true,
187
- };
188
- return obj;
189
- })
165
+ if (!isEmpty(androidContent)) {
166
+ const {
167
+ title: androidTitle = '',
168
+ message: androidMessage = '',
169
+ ctas: androidCta = {},
170
+ expandableDetails: androidExpandableDetails = {},
171
+ } = androidContent || {};
172
+ const {
173
+ style: androidStyle,
174
+ image: androidImage,
175
+ ctas: androidCtas,
176
+ } = androidExpandableDetails || {};
177
+ const androidCtaLength = androidCtas?.length;
178
+ setTitleAndroid(androidTitle);
179
+ setTemplateMessageAndroid(androidMessage);
180
+ setTemplateMediaType(
181
+ androidStyle === BIG_TEXT
182
+ ? INAPP_MEDIA_TYPES.TEXT
183
+ : INAPP_MEDIA_TYPES.IMAGE
190
184
  );
185
+ setInAppImageSrcAndroid(androidImage);
186
+ setDeepLinkValueAndroid(androidCta[0]?.actionLink);
187
+ setAddActionLinkAndroid(!isEmpty(androidCta) && true);
188
+ setButtonTypeAndroid(
189
+ androidCtaLength ? INAPP_BUTTON_TYPES.CTA : INAPP_BUTTON_TYPES.NONE
190
+ );
191
+ if (androidCtaLength > 0) {
192
+ setCtaDataAndroid(getCtaObject(androidCtas));
193
+ }
191
194
  }
192
195
  const iosContent = editContent?.IOS;
193
- const {
194
- title: iosTitle,
195
- message: iosMessage,
196
- cta: iosCta,
197
- expandableDetails: iosExpandableDetails,
198
- } = iosContent;
199
- setTitleIos(iosTitle);
200
- setTemplateMessageIos(iosMessage);
201
- setTemplateMediaType(iosExpandableDetails?.style === BIG_TEXT ? INAPP_MEDIA_TYPES.TEXT : INAPP_MEDIA_TYPES.IMAGE);
202
- setInAppImageSrcIos(iosExpandableDetails?.image);
203
- setButtonTypeIos(iosExpandableDetails?.ctas?.length ? INAPP_BUTTON_TYPES.CTA : INAPP_BUTTON_TYPES.NONE);
204
- setAddActionLinkIos(!isEmpty(iosCta) && true);
205
- setDeepLinkValueIos(iosCta?.actionLink);
206
- if (iosExpandableDetails?.ctas?.length > 0) {
207
- setCtaDataIos(
208
- iosExpandableDetails?.ctas?.map((cta, index) => {
209
- const { type, actionText, actionLink = "" } = cta;
210
- const obj = {
211
- index,
212
- text: actionText,
213
- url: actionLink,
214
- urlType: type,
215
- isSaved: true,
216
- };
217
- return obj;
218
- })
219
- );
196
+ if (!isEmpty(iosContent)) {
197
+ const {
198
+ title: iosTitle = '',
199
+ message: iosMessage = '',
200
+ ctas: iosCta = {},
201
+ expandableDetails: iosExpandableDetails = {},
202
+ } = iosContent || {};
203
+ const {
204
+ style: iosStyle,
205
+ image: iosImage,
206
+ ctas: iosCtas,
207
+ } = iosExpandableDetails || {};
208
+ const iosCtaLength = iosCtas?.length;
209
+ setTitleIos(iosTitle);
210
+ setTemplateMessageIos(iosMessage);
211
+ setTemplateMediaType(iosStyle === BIG_TEXT ? INAPP_MEDIA_TYPES.TEXT : INAPP_MEDIA_TYPES.IMAGE);
212
+ setInAppImageSrcIos(iosImage);
213
+ setButtonTypeIos(iosCtaLength ? INAPP_BUTTON_TYPES.CTA : INAPP_BUTTON_TYPES.NONE);
214
+ setAddActionLinkIos(!isEmpty(iosCta) && true);
215
+ setDeepLinkValueIos(iosCta[0]?.actionLink);
216
+ if (iosCtaLength > 0) {
217
+ setCtaDataIos(getCtaObject(iosCtas));
218
+ }
220
219
  }
221
220
  }
222
221
  }, [editData.templateDetails || templateData]);
@@ -359,6 +358,8 @@ export const InApp = (props) => {
359
358
  templateMessage={templateMessageAndroid}
360
359
  setTemplateMessage={setTemplateMessageAndroid}
361
360
  setTemplateMessageError={setTemplateMessageErrorAndroid}
361
+ templateTitleError={templateTitleErrorAndroid}
362
+ setTemplateTitleError={setTemplateTitleErrorAndroid}
362
363
  addActionLink={addActionLinkAndroid}
363
364
  setAddActionLink={setAddActionLinkAndroid}
364
365
  deepLink={deepLink}
@@ -373,6 +374,8 @@ export const InApp = (props) => {
373
374
  ),
374
375
  tab: <FormattedMessage {...messages.Android} />,
375
376
  key: ANDROID,
377
+ isSupported: get(accountData, 'selectedWeChatAccount.configs.android') === DEVICE_SUPPORTED,
378
+ // DEVICE_SUPPORTED is '1', which indicates if the particular account is supported, and '0' if the devive is not supported
376
379
  },
377
380
  {
378
381
  content: (
@@ -402,6 +405,8 @@ export const InApp = (props) => {
402
405
  templateMessage={templateMessageIos}
403
406
  setTemplateMessage={setTemplateMessageIos}
404
407
  setTemplateMessageError={setTemplateMessageErrorIos}
408
+ templateTitleError={templateTitleErrorIos}
409
+ setTemplateTitleError={setTemplateTitleErrorIos}
405
410
  addActionLink={addActionLinkIos}
406
411
  setAddActionLink={setAddActionLinkIos}
407
412
  deepLink={deepLink}
@@ -411,10 +416,12 @@ export const InApp = (props) => {
411
416
  tags={tags}
412
417
  onTagSelect={onTagSelect}
413
418
  handleOnTagsContextChange={handleOnTagsContextChange}
419
+ templateDescErrorHandler={templateDescErrorHandler}
414
420
  />
415
421
  ),
416
422
  tab: <FormattedMessage {...messages.Ios} />,
417
423
  key: IOS,
424
+ isSupported: get(accountData, 'selectedWeChatAccount.configs.ios') === DEVICE_SUPPORTED,
418
425
  },
419
426
  ];
420
427
 
@@ -499,24 +506,35 @@ export const InApp = (props) => {
499
506
  );
500
507
  };
501
508
 
502
- const isDisableDone = () => {
509
+ const isDisableDone = (device) => {
510
+ const isIosDevice = device === IOS;
511
+ const isAndroidDevice = device === ANDROID;
503
512
  //if template name is not entered
504
- if (templateName.trim() === '') {
513
+ if (isFullMode && templateName.trim() === '') {
505
514
  return true;
506
515
  }
507
516
  //if template message is not entered
508
517
  //for android
509
- if (panes === ANDROID && (templateMessageAndroid.trim() === '' || templateMessageErrorAndroid)) {
518
+ if (isAndroidDevice && (templateMessageAndroid.trim() === '' || templateMessageErrorAndroid)) {
510
519
  return true;
511
520
  }
512
- if (panes === IOS && (templateMessageIos.trim() === '' || templateMessageErrorIos)) {
521
+ if (isIosDevice && (templateMessageIos.trim() === '' || templateMessageErrorIos)) {
522
+ return true;
523
+ }//for ios
524
+
525
+ //if template title is not entered
526
+ //for android
527
+ if (isAndroidDevice && (titleAndroid.trim() === '' || templateTitleErrorAndroid)) {
528
+ return true;
529
+ }
530
+ if (isIosDevice && (titleIos.trim() === '' || templateTitleErrorIos)) {
513
531
  return true;
514
532
  }//for ios
515
533
  //if media type is image and the mediaType file is not uploaded
516
- if (panes === ANDROID && !(templateMediaType === INAPP_MEDIA_TYPES.TEXT) && inAppImageSrcAndroid === '') {
534
+ if (isAndroidDevice && !(templateMediaType === INAPP_MEDIA_TYPES.TEXT) && inAppImageSrcAndroid === '') {
517
535
  return true;
518
536
  }
519
- if (panes === IOS && !(templateMediaType === INAPP_MEDIA_TYPES.TEXT) && inAppImageSrcIos === '') {
537
+ if (isIosDevice && !(templateMediaType === INAPP_MEDIA_TYPES.TEXT) && inAppImageSrcIos === '') {
520
538
  return true;
521
539
  }
522
540
  //cta
@@ -581,7 +599,7 @@ export const InApp = (props) => {
581
599
  versions: {
582
600
  base: {
583
601
  content: {
584
- ANDROID: {
602
+ ANDROID: !isDisableDone(ANDROID) ? {
585
603
  ...commonDevicePayload,
586
604
  title: titleAndroid,
587
605
  message: templateMessageAndroid,
@@ -595,9 +613,11 @@ export const InApp = (props) => {
595
613
  }),
596
614
  },
597
615
  custom: [],
598
- cta: deepLinkValueAndroid ? {type: DEEP_LINK, actionLink: deepLinkValueAndroid} : {},
599
- },
600
- IOS: {
616
+ ...(deepLinkValueAndroid && {
617
+ ctas: [{type: DEEP_LINK, actionLink: deepLinkValueAndroid}],
618
+ }),
619
+ } : {},
620
+ IOS: !isDisableDone(IOS) ? {
601
621
  ...commonDevicePayload,
602
622
  title: titleIos,
603
623
  message: templateMessageIos,
@@ -611,8 +631,10 @@ export const InApp = (props) => {
611
631
  }),
612
632
  },
613
633
  custom: [],
614
- cta: deepLinkValueIos ? {type: DEEP_LINK, actionLink: deepLinkValueIos} : {},
615
- },
634
+ ...(deepLinkValueIos && {
635
+ ctas: [{type: DEEP_LINK, actionLink: deepLinkValueIos}],
636
+ }),
637
+ } : {},
616
638
  },
617
639
  },
618
640
  },
@@ -696,7 +718,7 @@ export const InApp = (props) => {
696
718
  {isFullMode && createModeContent}
697
719
  {/* device tab */}
698
720
  <CapTab
699
- panes={PANES}
721
+ panes={PANES.filter((devicePane) => devicePane?.isSupported === true)}
700
722
  onChange={(value) => {
701
723
  setPanes(value);
702
724
  }}
@@ -710,12 +732,12 @@ export const InApp = (props) => {
710
732
  {getPreviewSection()}
711
733
  </CapColumn>
712
734
  </CapRow>
713
- <div className="inapp-footer">
735
+ <div className={`inapp-footer ${!isFullMode && `inapp-footer-lib`}`}>
714
736
  {
715
737
  <>
716
738
  <CapButton
717
739
  onClick={onDoneCallback()}
718
- disabled={isDisableDone()}
740
+ disabled={isDisableDone(panes)}
719
741
  className="inapp-create-btn"
720
742
  >
721
743
  {isEditFlow ? (
@@ -725,7 +747,11 @@ export const InApp = (props) => {
725
747
  <FormattedMessage {...globalMessages.done} />
726
748
  )
727
749
  ) : (
728
- <FormattedMessage {...messages.create} />
750
+ isFullMode ? (
751
+ <FormattedMessage {...messages.create} />
752
+ ) : (
753
+ <FormattedMessage {...globalMessages.done} />
754
+ )
729
755
  )}
730
756
  </CapButton>
731
757
  </>
@@ -37,7 +37,6 @@
37
37
  .inapp-footer {
38
38
  background-color: $CAP_WHITE;
39
39
  bottom: 0;
40
- // position: fixed;
41
40
  width: 100%;
42
41
  padding: $CAP_SPACE_20 0;
43
42
  z-index: 1;
@@ -45,4 +44,7 @@
45
44
  .ant-btn {
46
45
  margin-right: $CAP_SPACE_16;
47
46
  }
47
+ }
48
+ .inapp-footer-lib {
49
+ position: fixed;
48
50
  }
@@ -96,4 +96,19 @@ export default defineMessages({
96
96
  defaultMessage:
97
97
  "Create a button that lets customers take an action",
98
98
  },
99
+ popup: {
100
+ id: `${prefix}.popup`,
101
+ defaultMessage:
102
+ "Pop-up",
103
+ },
104
+ header: {
105
+ id: `${prefix}.header`,
106
+ defaultMessage:
107
+ "Header",
108
+ },
109
+ footer: {
110
+ id: `${prefix}.footer`,
111
+ defaultMessage:
112
+ "Footer",
113
+ },
99
114
  });
@@ -14,6 +14,7 @@ import {
14
14
  location1,
15
15
  } from './mockData';
16
16
  import { metaEntities, getDefaultTags, injectedTags } from '../../Zalo/tests/mockData';
17
+ import { getCtaObject } from '../utils';
17
18
 
18
19
  const mockActions = {
19
20
  getTemplateInfoById: jest.fn(),
@@ -140,3 +141,23 @@ describe('Test activity inApp container', () => {
140
141
  expect(copyLink).toBeInTheDocument();
141
142
  });
142
143
  });
144
+ describe('test for getCtaObject function', () => {
145
+ it('getCtaObject function', () => {
146
+ const response = getCtaObject([{ type: "DEEP_LINK", actionText: "btn", actionLink: "url" }]);
147
+ expect(response).toEqual([{
148
+ index: 0,
149
+ text: "btn",
150
+ url: "url",
151
+ urlType: "DEEP_LINK",
152
+ isSaved: true,
153
+ }]);
154
+ const responseDefault = getCtaObject([{}]);
155
+ expect(responseDefault).toEqual([{
156
+ index: 0,
157
+ text: "",
158
+ url: "",
159
+ urlType: "",
160
+ isSaved: true,
161
+ }]);
162
+ });
163
+ });
@@ -171,7 +171,7 @@ export const accountData = {
171
171
  buttons: [
172
172
  {
173
173
  index: 0,
174
- type: "EXTERNAL_LINK",
174
+ type: "EXTERNAL_URL",
175
175
  text: "test",
176
176
  url: "https://nightly.intouch.capillarytech.com/creatives/ui/v2",
177
177
  label: "Test_1",
@@ -196,7 +196,7 @@ export const accountData = {
196
196
  buttons: [
197
197
  {
198
198
  index: 0,
199
- type: "EXTERNAL_LINK",
199
+ type: "EXTERNAL_URL",
200
200
  text: "test",
201
201
  url: "https://nightly.intouch.capillarytech.com/creatives/ui/v2",
202
202
  label: "Test_1",
@@ -247,7 +247,7 @@ export const accountData = {
247
247
  buttons: [
248
248
  {
249
249
  index: 0,
250
- type: "EXTERNAL_LINK",
250
+ type: "EXTERNAL_URL",
251
251
  text: "test",
252
252
  url: "https://nightly.intouch.capillarytech.com/creatives/ui/v2",
253
253
  label: "Test_1",
@@ -276,7 +276,7 @@ export const accountData = {
276
276
  buttons: [
277
277
  {
278
278
  index: 0,
279
- type: "EXTERNAL_LINK",
279
+ type: "EXTERNAL_URL",
280
280
  text: "testios",
281
281
  url: "https://nightly.intouch.capillarytech.com/creatives/ui/v2",
282
282
  label: "",
@@ -671,7 +671,7 @@ export const editData = {
671
671
  buttons: [
672
672
  {
673
673
  index: 0,
674
- type: "EXTERNAL_LINK",
674
+ type: "EXTERNAL_URL",
675
675
  text: "test",
676
676
  url: "https://nightly.intouch.capillarytech.com/creatives/ui/v2",
677
677
  label: "Test_1",
@@ -697,7 +697,7 @@ export const editData = {
697
697
  buttons: [
698
698
  {
699
699
  index: 0,
700
- type: "EXTERNAL_LINK",
700
+ type: "EXTERNAL_URL",
701
701
  text: "test",
702
702
  url: "https://nightly.intouch.capillarytech.com/creatives/ui/v2",
703
703
  label: "Test_1",
@@ -0,0 +1,12 @@
1
+ export const getCtaObject = (ctaData) =>
2
+ ctaData?.map((cta, index) => {
3
+ const { type = "", actionText = "", actionLink = "" } = cta;
4
+ const obj = {
5
+ index,
6
+ text: actionText,
7
+ url: actionLink,
8
+ urlType: type,
9
+ isSaved: true,
10
+ };
11
+ return obj;
12
+ });
@@ -49,6 +49,7 @@ import {
49
49
  CapInfoNote,
50
50
  CapImage,
51
51
  CapStatus,
52
+ CapColoredTag,
52
53
  } from '@capillarytech/cap-ui-library';
53
54
  import { makeSelectTemplates, makeSelectTemplatesResponse } from './selectors';
54
55
  import { makeSelectCreate as makeSelectCreateSms} from '../Sms/Create/selectors';
@@ -108,6 +109,7 @@ import {
108
109
  HOST_TWILIO,
109
110
  HOST_GUPSHUP,
110
111
  } from '../Whatsapp/constants';
112
+ import { INAPP_LAYOUT_DETAILS } from '../InApp/constants';
111
113
  import { ZALO_STATUS_OPTIONS, ZALO_STATUSES } from '../Zalo/constants';
112
114
  import { getWhatsappContent, getWhatsappStatus, getWhatsappCategory, getWhatsappCta, getWhatsappQuickReply } from '../Whatsapp/utils';
113
115
  import { getRCSContent } from '../Rcs/utils';
@@ -823,7 +825,7 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
823
825
  queryParams.wecrmToken = this.props.Templates.selectedWeChatAccount.configs.wecrm_token;
824
826
  queryParams.originalId = this.props.Templates.selectedWeChatAccount.sourceAccountIdentifier;
825
827
  }
826
- if (([MOBILE_PUSH_LOWERCASE, INAPP_LOWERCASE.includes](this.state.channel.toLowerCase())) && !isEmpty(this.props.Templates.selectedWeChatAccount)) {
828
+ if (([MOBILE_PUSH_LOWERCASE, INAPP_LOWERCASE].includes(this.state.channel.toLowerCase())) && !isEmpty(this.props.Templates.selectedWeChatAccount)) {
827
829
  queryParams.accountId = this.props.Templates.selectedWeChatAccount.id;
828
830
  if (this.state.mode) {
829
831
  queryParams.mode = this.state.mode.toLowerCase();
@@ -1004,22 +1006,73 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
1004
1006
  );
1005
1007
 
1006
1008
  const cardDataList = filteredTemplates && filteredTemplates.length ? map(filteredTemplates, (template) => {
1007
- const templateData =
1008
- {
1009
- key: `${currentChannel}-card-${template?.name}`,
1010
- title: <span title={template?.name} >{template?.name}</span>,
1011
- extra: [
1012
- <CapTooltip title={this.state.channel.toLowerCase() === ZALO_LOWERCASE ? <div className='zalo-view-tooltip'>{this.props.intl.formatMessage(messages.zaloPreview)}</div> : ''}>
1013
- <CapIcon
1014
- className={`view-${channelLowerCase}`}
1015
- style={{ marginRight: '16px' }}
1016
- type="eye"
1017
- onClick={() => { if (!this.props.isFullMode || this.props.isDltFromRcs) { this.props.handlePeviewTemplate(template); } else { handlers.handlePreviewClick(template); } }}
1018
- />
1019
- </CapTooltip>,
1020
- ],
1021
- hoverOption: <CapButton className={this.props.isFullMode ? `edit-${channelLowerCase}` : `select-${channelLowerCase}`} onClick={(e) => handlers.handleEditClick(e, template, undefined, undefined, {account: this.state.selectedAccount})}>{hoverButtonText}</CapButton>,
1022
- };
1009
+ const androidBodyType = get(template, 'versions.base.content.ANDROID.bodyType');
1010
+ const iosBodyType = get(template, 'versions.base.content.IOS.bodyType');
1011
+ const inappBodyType = androidBodyType || iosBodyType;
1012
+ const templateData = {
1013
+ key: `${currentChannel}-card-${template?.name}`,
1014
+ title: (
1015
+ <span title={template?.name}>
1016
+ {template?.name}
1017
+ {currentChannel === INAPP && (
1018
+ <CapRow>
1019
+ <CapColoredTag
1020
+ tagColor={INAPP_LAYOUT_DETAILS[inappBodyType]?.tagColor}
1021
+ tagTextColor={
1022
+ INAPP_LAYOUT_DETAILS[inappBodyType]?.tagTextColor
1023
+ }
1024
+ tagHeight="1.25rem"
1025
+ tagFontSize="12px"
1026
+ >
1027
+ {INAPP_LAYOUT_DETAILS[inappBodyType]?.text}
1028
+ </CapColoredTag>
1029
+ </CapRow>
1030
+ )}
1031
+ </span>
1032
+ ),
1033
+ extra: [
1034
+ <CapTooltip
1035
+ title={
1036
+ this.state.channel.toLowerCase() === ZALO_LOWERCASE ? (
1037
+ <div className="zalo-view-tooltip">
1038
+ {this.props.intl.formatMessage(messages.zaloPreview)}
1039
+ </div>
1040
+ ) : (
1041
+ ""
1042
+ )
1043
+ }
1044
+ >
1045
+ <CapIcon
1046
+ className={`view-${channelLowerCase}`}
1047
+ style={{ marginRight: "16px" }}
1048
+ type="eye"
1049
+ onClick={() => {
1050
+ if (!this.props.isFullMode || this.props.isDltFromRcs) {
1051
+ this.props.handlePeviewTemplate(template);
1052
+ } else {
1053
+ handlers.handlePreviewClick(template);
1054
+ }
1055
+ }}
1056
+ />
1057
+ </CapTooltip>,
1058
+ ],
1059
+ hoverOption: (
1060
+ <CapButton
1061
+ className={
1062
+ this.props.isFullMode
1063
+ ? `edit-${channelLowerCase}`
1064
+ : `select-${channelLowerCase}`
1065
+ }
1066
+ onClick={(e) =>
1067
+ handlers.handleEditClick(e, template, undefined, undefined, {
1068
+ account: this.state.selectedAccount,
1069
+ })
1070
+ }
1071
+ >
1072
+ {hoverButtonText}
1073
+ </CapButton>
1074
+ ),
1075
+ };
1023
1076
  const {
1024
1077
  versions: {
1025
1078
  base: {