@capillarytech/creatives-library 7.17.82 → 7.17.84

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.82",
4
+ "version": "7.17.84",
5
5
  "description": "Capillary creatives ui",
6
6
  "main": "./index.js",
7
7
  "module": "./index.es.js",
package/services/api.js CHANGED
@@ -504,3 +504,8 @@ export const getTemplateInfoById = ({id, username, oa_id, token}) => {
504
504
  const url = `${API_ENDPOINT}/templates/${id}/Zalo?username=${username}&oa_id=${oa_id}&token=${token}`;
505
505
  return request(url, getAPICallObject('GET'));
506
506
  };
507
+
508
+ export const getMetaTags = ({previewUrl}) => {
509
+ const url = `${API_ENDPOINT}/common/getMetaTags?url=${previewUrl}`;
510
+ return request(url, getAPICallObject('GET'));
511
+ };
@@ -2,7 +2,8 @@ import {
2
2
  getSenderDetails,
3
3
  uploadFile,
4
4
  getCdnTransformationConfig,
5
- createWhatsappTemplate
5
+ createWhatsappTemplate,
6
+ getMetaTags,
6
7
  } from '../api';
7
8
  import { mockData } from './mockData';
8
9
  const sampleFile = require('../../assets/line.png');
@@ -44,3 +45,10 @@ describe('createWhatsappTemplate -- Test with valid responses', () => {
44
45
  createWhatsappTemplate(sampleFile, mockData.createWhatsappPayload),
45
46
  ).toEqual(Promise.resolve()));
46
47
  });
48
+
49
+ describe('getMetaTags -- Test with valid responses', () => {
50
+ it('Should return correct response', () =>
51
+ expect(
52
+ getMetaTags({previewUrl: 'https://capillarytech.com'}),
53
+ ).toEqual(Promise.resolve()));
54
+ });
@@ -3,7 +3,7 @@
3
3
  .cap-whatsapp-quick-reply {
4
4
  border: solid 0.063rem $CAP_G06;
5
5
  margin-left: $CAP_SPACE_24;
6
- margin-top: $CAP_SPACE_24;
6
+ margin-top: 0.75rem;
7
7
  border-radius: 0.285rem;
8
8
  .whatsapp-button-text-container {
9
9
  padding: $CAP_SPACE_16 $CAP_SPACE_24;
@@ -39,5 +39,5 @@
39
39
  .whatsapp-quick-reply-edit-container {
40
40
  padding: $CAP_SPACE_12;
41
41
  margin-left: 0;
42
- margin-top: $CAP_SPACE_16;
42
+ margin-top: 0.75rem;
43
43
  }
@@ -276,6 +276,7 @@
276
276
  align-content: center;
277
277
  justify-content: center;
278
278
  margin-bottom: 4px;
279
+ align-items: center;
279
280
  svg {
280
281
  margin-right: $CAP_SPACE_04;
281
282
  }
@@ -520,4 +521,24 @@
520
521
  .zalo-preview-container-campaign {
521
522
  padding-left: 0px;
522
523
  padding-right: 4.563rem;
524
+ }
525
+
526
+ .url-preview-image {
527
+ width: 100%;
528
+ height: 100%;
529
+ background-color: hsl(0, 0%, 90%);
530
+ }
531
+
532
+ .url-preview-description {
533
+ font-size: 0.6rem;
534
+ font-weight: $FONT_WEIGHT_REGULAR;
535
+ color: $FONT_COLOR_01;
536
+ margin: 0.13rem 0;
537
+ }
538
+
539
+ .url-preview {
540
+ font-size: 0.5rem;
541
+ font-weight: $FONT_WEIGHT_REGULAR;
542
+ color: $FONT_COLOR_02;
543
+ margin-bottom: $CAP_SPACE_08;
523
544
  }
@@ -11,6 +11,7 @@ import _ from 'lodash';
11
11
  import { injectIntl, FormattedMessage, intlShape } from 'react-intl';
12
12
  // import styled from 'styled-components';
13
13
  import { CapColumn, CapRow, CapHeading, CapIcon, CapButton, CapImage, CapLabel, CapDivider, CapTooltip } from '@capillarytech/cap-ui-library';
14
+ import { isEmpty } from 'lodash';
14
15
  import './_templatePreview.scss';
15
16
  import {updateCharCount} from '../../utils/smsCharCountV2';
16
17
  import messages from './messages';
@@ -342,6 +343,38 @@ export class TemplatePreview extends React.Component { // eslint-disable-line re
342
343
  );
343
344
  };
344
345
 
346
+ const renderUrlPreview = (metaTags) => {
347
+ const renderArray = [];
348
+ if (!isEmpty(metaTags)) {
349
+ const { image = '', title = '', description = '', url = '' } = metaTags || {};
350
+ if (image) {
351
+ renderArray.push(
352
+ <CapImage
353
+ src={image}
354
+ alt={formatMessage(messages.previewUrlMetaImage)}
355
+ className="url-preview-image"
356
+ />
357
+ );
358
+ }
359
+ if (title) {
360
+ renderArray.push(
361
+ <CapLabel type="label8">{title}</CapLabel>
362
+ );
363
+ }
364
+ if (description) {
365
+ renderArray.push(
366
+ <CapLabel className="url-preview-description">{description}</CapLabel>
367
+ );
368
+ }
369
+ if (url) {
370
+ renderArray.push(
371
+ <CapLabel className="url-preview">{url}</CapLabel>
372
+ );
373
+ }
374
+ }
375
+ return renderArray;
376
+ };
377
+
345
378
  const handlePreview = () => {
346
379
  const {templatePreviewUrl = ''} = templateData;
347
380
  handlePreviewInNewTab(templatePreviewUrl);
@@ -756,6 +789,9 @@ export class TemplatePreview extends React.Component { // eslint-disable-line re
756
789
  <div className="msg-container whatsapp-message-container">
757
790
  <div className="message-pop align-left" style={whatsappSectionStyle}>
758
791
  <div className="whatsapp-content">
792
+ {content?.showUrlPreview && (
793
+ renderUrlPreview(content?.metaTagsDetails)
794
+ )}
759
795
  {content?.whatsappImageSrc && (
760
796
  <CapImage
761
797
  src={content.whatsappImageSrc}
@@ -82,4 +82,8 @@ export default defineMessages({
82
82
  id: 'creatives.componentsV2.TemplatePreview.videoPreviewTooltip',
83
83
  defaultMessage: "This is just for preview purposes, video cannot be played here",
84
84
  },
85
+ previewUrlMetaImage: {
86
+ id: 'creatives.componentsV2.TemplatePreview.previewUrlMetaImage',
87
+ defaultMessage: 'Preview url meta image',
88
+ },
85
89
  });
@@ -411,6 +411,7 @@ export class Creatives extends React.Component {
411
411
  buttons = [],
412
412
  mediaType = 'TEXT',
413
413
  whatsappMedia = {},
414
+ isPreviewUrl = false,
414
415
  } = {},
415
416
  } = templateData;
416
417
  const mediaParams = {};
@@ -476,6 +477,7 @@ export class Creatives extends React.Component {
476
477
  : template,
477
478
  },
478
479
  ],
480
+ isPreviewUrl,
479
481
  },
480
482
  },
481
483
  },
@@ -677,7 +679,8 @@ export class Creatives extends React.Component {
677
679
  headerVarMapped = {},
678
680
  footer = '',
679
681
  headerTemplate = '',
680
- } = {}
682
+ } = {},
683
+ isPreviewUrl = false,
681
684
  } = cloneDeep(versions.base.content.whatsapp);
682
685
 
683
686
  const modifiedButtons = cloneDeep(buttons).map((btn) => {
@@ -747,6 +750,7 @@ export class Creatives extends React.Component {
747
750
  buttons: modifiedButtons,
748
751
  mediaType,
749
752
  whatsappMedia,
753
+ isPreviewUrl,
750
754
  },
751
755
  };
752
756
  }
@@ -6,6 +6,8 @@ import {
6
6
  WHATSAPP,
7
7
  UPLOAD_WHATSAPP_ASSET_REQUEST,
8
8
  CLEAR_WHATSAPP_ASSET,
9
+ URL_META_TAGS_REQUEST,
10
+ URL_META_TAGS_RESET,
9
11
  } from './constants';
10
12
 
11
13
  export function createWhatsappTemplate(payload, callback, gupshupMediaFile) {
@@ -55,3 +57,17 @@ export const clearWhatsappAsset = (templateType) => ({
55
57
  type: CLEAR_WHATSAPP_ASSET,
56
58
  templateType,
57
59
  });
60
+
61
+ export function getMetaTags({previewUrl, callBack}) {
62
+ return {
63
+ type: URL_META_TAGS_REQUEST,
64
+ previewUrl,
65
+ callBack,
66
+ };
67
+ }
68
+
69
+ export function resetMetaTags() {
70
+ return {
71
+ type: URL_META_TAGS_RESET,
72
+ };
73
+ }
@@ -31,6 +31,12 @@ export const UPLOAD_WHATSAPP_ASSET_SUCCESS = `${prefix}/UPLOAD_WHATSAPP_ASSET_SU
31
31
  export const UPLOAD_WHATSAPP_ASSET_FAILURE = `${prefix}/UPLOAD_WHATSAPP_ASSET_FAILURE`;
32
32
  export const CLEAR_WHATSAPP_ASSET = `${prefix}/CLEAR_WHATSAPP_ASSET`;
33
33
 
34
+ //For meta tags
35
+ export const URL_META_TAGS_REQUEST = `${prefix}/URL_META_TAGS_REQUEST`;
36
+ export const URL_META_TAGS_SUCCESS = `${prefix}/URL_META_TAGS_SUCCESS`;
37
+ export const URL_META_TAGS_FAILURE = `${prefix}/URL_META_TAGS_FAILURE`;
38
+ export const URL_META_TAGS_RESET = `${prefix}/URL_META_TAGS_RESET`;
39
+
34
40
  export const STATUS = 'status';
35
41
  export const CATEGORY = 'category';
36
42
 
@@ -25,6 +25,7 @@ import CapAlert from '@capillarytech/cap-ui-library/CapAlert';
25
25
  import CapCheckbox from '@capillarytech/cap-ui-library/CapCheckbox';
26
26
  import CapLink from '@capillarytech/cap-ui-library/CapLink';
27
27
  import moment from 'moment';
28
+ import debounce from 'lodash/debounce';
28
29
  import {
29
30
  CAP_SPACE_04,
30
31
  CAP_SPACE_16,
@@ -181,9 +182,12 @@ export const Whatsapp = (props) => {
181
182
  const [headerTextAreaId, setHeaderTextAreaId] = useState('');
182
183
  const [isHeaderTagValidationError, updateIsHeaderTagValidationError] =
183
184
  useState(false);
185
+ const [showUrlPreview, setShowUrlPreview] = useState(false);
186
+ const [previewUrl, setPreviewUrl] = useState('');
184
187
 
185
188
  const validVarRegex = /{{([1-9]|1[0-9])}}/g;
186
189
  const headerValidVarRegex = /{{(1)}}/g;
190
+ const previewUrlMatchingRegex = /(http|ftp|https):\/\/([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:\/~+#-]*[\w@?^=%&\/~+#-])/g;
187
191
 
188
192
  const isBtnTypeCta = buttonType === WHATSAPP_BUTTON_TYPES.CTA;
189
193
  const isBtnTypeQuickReply = buttonType === WHATSAPP_BUTTON_TYPES.QUICK_REPLY;
@@ -268,6 +272,7 @@ export const Whatsapp = (props) => {
268
272
  videoPreviewImg = '',
269
273
  whatsappDocParams = {},
270
274
  whatsappMedia: { header = '', footer = '' } = {},
275
+ isPreviewUrl = false,
271
276
  } = editContent;
272
277
  setTemplateCategory(category);
273
278
  setTemplateStatus(status);
@@ -291,6 +296,7 @@ export const Whatsapp = (props) => {
291
296
  setButtonType(btnType);
292
297
  setTemplateFooter(footer);
293
298
  setTemplateHeader(header);
299
+ setShowUrlPreview(isPreviewUrl);
294
300
  if (btnType === WHATSAPP_BUTTON_TYPES.CTA && buttons.length > 0) {
295
301
  setCtadata(
296
302
  buttons.map((cta) => {
@@ -425,6 +431,11 @@ export const Whatsapp = (props) => {
425
431
  arr[key.slice(key.indexOf('_') + 1)] = varMap[key];
426
432
  }
427
433
  }
434
+ // extract preview url from message
435
+ if (arr?.length) {
436
+ const validUrls = arr.join("").match(previewUrlMatchingRegex) || [];
437
+ setPreviewUrl(validUrls?.[0] || '')
438
+ }
428
439
  setUpdatedSmsEditor(arr);
429
440
  }
430
441
  }, [tempMsgArray]);
@@ -467,7 +478,7 @@ export const Whatsapp = (props) => {
467
478
 
468
479
  const tagValidation = (contentData, regex, type) => {
469
480
  if (contentData?.length > 0 && !contentData.join("").match(regex)) {
470
- tagValidationResponse =
481
+ const validationResponse =
471
482
  validateTags({
472
483
  content: contentData.join(""),
473
484
  tagsParam: tags,
@@ -475,16 +486,49 @@ export const Whatsapp = (props) => {
475
486
  location,
476
487
  tagModule: getDefaultTags,
477
488
  }) || {};
478
- type === HEADER_TEXT
479
- ? updateIsHeaderTagValidationError(
480
- tagValidationResponse?.unsupportedTags?.length > 0
481
- )
482
- : updateIsTagValidationError(
483
- tagValidationResponse?.unsupportedTags?.length > 0
484
- );
489
+ const unsupportedTagsLengthCheck =
490
+ validationResponse?.unsupportedTags?.length > 0;
491
+ if (type === HEADER_TEXT) {
492
+ headerTagValidationResponse = validationResponse;
493
+ updateIsHeaderTagValidationError(unsupportedTagsLengthCheck);
494
+ } else {
495
+ tagValidationResponse = validationResponse;
496
+ updateIsTagValidationError(unsupportedTagsLengthCheck);
497
+ }
485
498
  }
486
499
  };
487
500
 
501
+ // as per change in message body we filter out url using regex
502
+ useEffect(() => {
503
+ if (updatedSmsEditor?.length > 0) {
504
+ const previewUrlArr = updatedSmsEditor.join("").match(previewUrlMatchingRegex) || [];
505
+ if (previewUrlArr?.length > 0) {
506
+ setPreviewUrl(previewUrlArr[0]);
507
+ } else {
508
+ setPreviewUrl('');
509
+ }
510
+ }
511
+ }, [updatedSmsEditor])
512
+
513
+ const debounceFn = useCallback(
514
+ debounce(url => {
515
+ actions.getMetaTags({
516
+ previewUrl: url,
517
+ callBack: actionCallback,
518
+ })
519
+ }, 500),
520
+ [],
521
+ );
522
+
523
+ // as per change in url and preview checkbox we call api and extract the meta information of url
524
+ useEffect(() => {
525
+ if (!isEmpty(previewUrl) && showUrlPreview) {
526
+ debounceFn(previewUrl);
527
+ } else {
528
+ actions.resetMetaTags();
529
+ }
530
+ }, [previewUrl, showUrlPreview])
531
+
488
532
  //performs tag validation
489
533
  useEffect(() => {
490
534
  if (!isFullMode)
@@ -787,6 +831,10 @@ export const Whatsapp = (props) => {
787
831
  setTemplateMessageError(error);
788
832
  };
789
833
 
834
+ const previewUrlHandler = ({ target: { checked } }) => {
835
+ setShowUrlPreview(checked);
836
+ }
837
+
790
838
  const renderUnsubscribeText = () => {
791
839
  const isDisabled =
792
840
  isEditFlow ||
@@ -1246,6 +1294,9 @@ export const Whatsapp = (props) => {
1246
1294
  footer: templateFooter || ""
1247
1295
  }),
1248
1296
  },
1297
+ ...(isEditFlow && !isFullMode && {
1298
+ isPreviewUrl: showUrlPreview
1299
+ })
1249
1300
  },
1250
1301
  },
1251
1302
  },
@@ -1812,7 +1863,7 @@ export const Whatsapp = (props) => {
1812
1863
  {isHeaderTagValidationError && tagValidationErrorMessage(HEADER_TEXT)}
1813
1864
  {computeTextLength(HEADER_TEXT) > TEMPLATE_HEADER_MAX_LENGTH && (
1814
1865
  <CapError>
1815
- {formatMessage(messages.templateMessageLengthError)}
1866
+ {formatMessage(messages.templateHeaderLengthError)}
1816
1867
  </CapError>
1817
1868
  )}
1818
1869
  </>
@@ -1859,6 +1910,19 @@ export const Whatsapp = (props) => {
1859
1910
  ) : (
1860
1911
  ""
1861
1912
  )}
1913
+ <CapRow>
1914
+ <CapCheckbox
1915
+ className={`whatsapp-unsubscribe-checkbox ${'whatsapp-create-unsubscribe-checkbox'}`}
1916
+ onChange={previewUrlHandler}
1917
+ checked={showUrlPreview}
1918
+ disabled={!isMediaTypeText}
1919
+ autoFocus={true}
1920
+ >
1921
+ <span className="whatsapp-render-url-preview-text">
1922
+ {formatMessage(messages.showUrlPreview)}
1923
+ </span>
1924
+ </CapCheckbox>
1925
+ </CapRow>
1862
1926
  {templateFooter && isHostIsNotTwilio && (
1863
1927
  <>
1864
1928
  <CapHeader
@@ -1922,6 +1986,7 @@ export const Whatsapp = (props) => {
1922
1986
 
1923
1987
  //used by create and edit
1924
1988
  const getPreviewSection = () => {
1989
+ const { metaTagsDetails = {} } = editData || {};
1925
1990
  const templateMsg = (
1926
1991
  <>
1927
1992
  <CapLabel type="label5">
@@ -1973,6 +2038,10 @@ export const Whatsapp = (props) => {
1973
2038
  ...(isBtnTypeQuickReply && {
1974
2039
  quickReplyData,
1975
2040
  }),
2041
+ ...(isMediaTypeText && showUrlPreview && {
2042
+ showUrlPreview,
2043
+ metaTagsDetails,
2044
+ }),
1976
2045
  }}
1977
2046
  whatsappContentLen={computeTextLength()}
1978
2047
  whatsappAccountName={accountName}
@@ -130,6 +130,7 @@
130
130
  .whatsapp-button-quick-reply {
131
131
  display: inline-grid;
132
132
  margin-top: $CAP_SPACE_24;
133
+ margin-bottom: 0.75rem;
133
134
  }
134
135
 
135
136
  .whatsapp-optional-label {
@@ -190,11 +191,17 @@
190
191
  .whatsapp-template-footer-preview {
191
192
  color: $CAP_G04;
192
193
  font-weight: $FONT_WEIGHT_REGULAR;
193
- font-size: 0.571rem;
194
+ font-size: 0.5rem;
194
195
  margin-top: $CAP_SPACE_08;
195
196
  }
196
197
 
197
198
  .whatsapp-text-field_spacing {
198
199
  margin-left: $CAP_SPACE_04;
199
200
  }
201
+
202
+ .whatsapp-render-url-preview-text {
203
+ color: $CAP_G01;
204
+ font-size: $FONT_SIZE_M;
205
+ font-weight: $FONT_WEIGHT_MEDIUM;
206
+ }
200
207
  }
@@ -659,5 +659,9 @@ export default defineMessages({
659
659
  quickReplyButtons: {
660
660
  id: `${prefix}.quickReplyButtons`,
661
661
  defaultMessage: 'Quick reply buttons',
662
- }
662
+ },
663
+ showUrlPreview: {
664
+ id: `${prefix}.showUrlPreview`,
665
+ defaultMessage: 'Show URL preview',
666
+ },
663
667
  });
@@ -12,11 +12,18 @@ import {
12
12
  UPLOAD_WHATSAPP_ASSET_SUCCESS,
13
13
  UPLOAD_WHATSAPP_ASSET_FAILURE,
14
14
  CLEAR_WHATSAPP_ASSET,
15
+ URL_META_TAGS_REQUEST,
16
+ URL_META_TAGS_SUCCESS,
17
+ URL_META_TAGS_FAILURE,
18
+ URL_META_TAGS_RESET,
15
19
  } from './constants';
16
20
 
17
21
  const initialState = fromJS({
18
22
  uploadedAssetData: {},
19
23
  createTemplateInProgress: false,
24
+ getMetaTagsRequest: false,
25
+ metaTagsDetails: {},
26
+ getMetaTagsError: '',
20
27
  });
21
28
 
22
29
  function whatsappReducer(state = initialState, action) {
@@ -51,6 +58,18 @@ function whatsappReducer(state = initialState, action) {
51
58
  .set('templateDetails', action.data);
52
59
  case GET_TEMPLATE_DETAILS_FAILURE:
53
60
  return state.set('getTemplateDetailsInProgress', false);
61
+ case URL_META_TAGS_REQUEST:
62
+ return state.set('getMetaTagsRequest', true)
63
+ .set('metaTagsDetails', {});
64
+ case URL_META_TAGS_SUCCESS:
65
+ return state.set('getMetaTagsRequest', false)
66
+ .set('metaTagsDetails', action?.data);
67
+ case URL_META_TAGS_FAILURE:
68
+ return state.set('getMetaTagsRequest', false)
69
+ .set('getMetaTagsError', action?.error)
70
+ .set('metaTagsDetails', {});
71
+ case URL_META_TAGS_RESET:
72
+ return state.set('metaTagsDetails', {});
54
73
  case RESET_EDIT_TEMPLATE:
55
74
  return state.set('templateDetails', {});
56
75
  case UPLOAD_WHATSAPP_ASSET_REQUEST:
@@ -12,6 +12,9 @@ import {
12
12
  UPLOAD_WHATSAPP_ASSET_REQUEST,
13
13
  UPLOAD_WHATSAPP_ASSET_SUCCESS,
14
14
  UPLOAD_WHATSAPP_ASSET_FAILURE,
15
+ URL_META_TAGS_REQUEST,
16
+ URL_META_TAGS_SUCCESS,
17
+ URL_META_TAGS_FAILURE,
15
18
  } from './constants';
16
19
 
17
20
  export function* uploadWhatsappAsset(params) {
@@ -90,11 +93,46 @@ export function* getTemplateDetails({ id }) {
90
93
  }
91
94
  }
92
95
 
96
+ //For getMetaTags
97
+ export function* getMetaTagsDetails({ previewUrl, callBack }) {
98
+ try {
99
+ const result = yield call(Api.getMetaTags, {
100
+ previewUrl,
101
+ });
102
+ if (result?.success) {
103
+ yield put({
104
+ type: URL_META_TAGS_SUCCESS,
105
+ data: result?.response,
106
+ });
107
+ } else {
108
+ if (callBack) {
109
+ callBack({errorMessage: result?.message});
110
+ }
111
+ yield put({
112
+ type: URL_META_TAGS_FAILURE,
113
+ error: result?.message,
114
+ });
115
+ }
116
+ } catch (error) {
117
+ if (callBack) {
118
+ callBack({errorMessage: error});
119
+ }
120
+ yield put({ type: URL_META_TAGS_FAILURE, error });
121
+ }
122
+ }
123
+
93
124
  function* watchGetTemplateDetails() {
94
- const watcher = yield takeLatest(
125
+ yield takeLatest(
95
126
  GET_TEMPLATE_DETAILS_REQUEST,
96
127
  getTemplateDetails,
97
128
  );
129
+ }
130
+
131
+ export function* watchGetMetaTagsDetails() {
132
+ const watcher = yield takeLatest(
133
+ URL_META_TAGS_REQUEST,
134
+ getMetaTagsDetails,
135
+ );
98
136
  yield take(LOCATION_CHANGE);
99
137
  yield cancel(watcher);
100
138
  }
@@ -103,4 +141,5 @@ export default [
103
141
  watchCreateTemplate,
104
142
  watchGetTemplateDetails,
105
143
  watchUploadWhatsappAsset,
144
+ watchGetMetaTagsDetails,
106
145
  ];
@@ -61,6 +61,7 @@
61
61
  display: flex;
62
62
  justify-content: center;
63
63
  font-size: $FONT_SIZE_M;
64
+ align-items: center;
64
65
  svg {
65
66
  margin-right: $CAP_SPACE_04;
66
67
  }