@capillarytech/creatives-library 7.10.54 → 7.10.55

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.
@@ -700,6 +700,9 @@ function SlideBoxContent(props) {
700
700
  {isEditWhatsapp && (<Whatsapp
701
701
  isFullMode={isFullMode}
702
702
  templateData={templateData}
703
+ getFormData={getFormData}
704
+ getDefaultTags={type}
705
+ forwardedTags={forwardedTags}
703
706
  params={{
704
707
  id: templateData._id,
705
708
  }}
@@ -22,7 +22,6 @@ const StyledLabel = styled(CapLabelInline)`
22
22
  const PrefixWrapper = styled.div`
23
23
  margin-right: 16px;
24
24
  `;
25
-
26
25
  const renderWhatsappData = (type, value) => (
27
26
  <StyledLabel type={type}>
28
27
  {value}
@@ -31,6 +31,7 @@ import { IMAGE as LINE_IMAGE, IMAGE_MAP, IMAGE_CAROUSEL, VIDEO as LINE_VIDEO, TE
31
31
  import {IMAGE, VIDEO } from '../Facebook/Advertisement/constant';
32
32
  import { CREATIVE } from '../Facebook/constants';
33
33
  import { LOYALTY } from '../App/constants';
34
+ import { WHATSAPP_STATUSES } from '../Whatsapp/constants';
34
35
 
35
36
 
36
37
  const classPrefix = 'add-creatives-section';
@@ -364,6 +365,42 @@ class Creatives extends React.Component {
364
365
  };
365
366
  break;
366
367
  }
368
+ case constants.WHATSAPP: {
369
+ const {
370
+ templateConfigs: {
371
+ name,
372
+ template,
373
+ varMapped,
374
+ language,
375
+ category,
376
+ mediaType
377
+ }
378
+ } = templateData;
379
+ creativesTemplateData = {
380
+ type: constants.WHATSAPP,
381
+ edit: true,
382
+ name,
383
+ versions: {
384
+ base: {
385
+ content: {
386
+ whatsapp: {
387
+ status: WHATSAPP_STATUSES.approved,
388
+ category,
389
+ varMapped,
390
+ mediaType,
391
+ languages: [
392
+ {
393
+ language,
394
+ content: `$'${template}'`,
395
+ }
396
+ ]
397
+ }
398
+ },
399
+ },
400
+ },
401
+ };
402
+ break;
403
+ }
367
404
  default:
368
405
  break;
369
406
  }
@@ -495,6 +532,38 @@ class Creatives extends React.Component {
495
532
  };
496
533
  }
497
534
  break;
535
+ case constants.WHATSAPP:
536
+ if (template.value) {
537
+ const { Templates, templateData: templateDataProps } = this.props;
538
+ const { accountDetails: selectedAccountDetails, accountId: selectedAccountId } = templateDataProps || {};
539
+ const selectedWhatsappAccount = Templates?.selectedWhatsappAccount;
540
+ const accountDetails = (selectedWhatsappAccount ? selectedWhatsappAccount : selectedAccountDetails);
541
+ const accountId = selectedAccountId || (selectedWhatsappAccount?.id || '');
542
+ const { versions } = template.value;
543
+ const {
544
+ languages,
545
+ mediaType,
546
+ category,
547
+ templateEditor,
548
+ varMapped
549
+ } = cloneDeep(versions.base.content.whatsapp);
550
+ templateData = {
551
+ channel,
552
+ accountId,
553
+ accountName: accountDetails.name,
554
+ messageBody: languages[0].content,
555
+ templateConfigs: {
556
+ id: template._id,
557
+ name: template?.value?.name,
558
+ template, templateEditor,
559
+ varMapped,
560
+ category,
561
+ language: languages[0].language,
562
+ mediaType,
563
+ }
564
+ };
565
+ }
566
+ break;
498
567
  case constants.FACEBOOK: {
499
568
  if (template.value) {
500
569
  const FacebookAd = template?.value?.versions?.base?.content?.FacebookAd;
@@ -151,6 +151,20 @@
151
151
 
152
152
  }
153
153
  }
154
+
155
+ .create-new-link{
156
+ .ant-anchor-link {
157
+ display: flex;
158
+
159
+ .ant-anchor-link-title {
160
+ margin: 0;
161
+ }
162
+
163
+ .cap-link-v2-suffix {
164
+ margin-top: -2px;
165
+ }
166
+ }
167
+ }
154
168
  }
155
169
 
156
170
  .card-title {
@@ -56,6 +56,7 @@ import { makeSelectEdit } from '../Sms/Edit/selectors';
56
56
  import { makeSelectLine } from '../Line/Container/selectors';
57
57
  import { makeSelectViber } from '../Viber/selectors';
58
58
  import { UserIsAuthenticated } from '../../utils/authWrapper';
59
+ import { getObjFromQueryParams } from '../../utils/v2common';
59
60
  import messages from './messages';
60
61
  import {checkUnicode} from '../../utils/smsCharCountV2';
61
62
  import * as actions from './actions';
@@ -84,8 +85,9 @@ import {
84
85
  CHANNEL_EDIT_TRACK_MAPPING,
85
86
  VIBER as VIBER_CHANNEL,
86
87
  FACEBOOK as FACEBOOK_CHANNEL,
88
+ CREATE,
87
89
  } from '../App/constants';
88
- import { MAX_WHATSAPP_TEMPLATES } from './constants';
90
+ import { MAX_WHATSAPP_TEMPLATES, WARNING_WHATSAPP_TEMPLATES } from './constants';
89
91
  import {
90
92
  CATEGORY_OPTIONS,
91
93
  STATUS_OPTIONS,
@@ -265,6 +267,13 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
265
267
  if (this.props.location.query.type === 'embedded' && this.isEnabledInLibraryModule("setLocale")) {
266
268
  this.setLocale();
267
269
  }
270
+
271
+ // opening the create slidebox based on query params
272
+ const queryItems = getObjFromQueryParams(location.search);
273
+ if (queryItems.channel === WHATSAPP_LOWERCASE && queryItems.mode === CREATE) {
274
+ this.createTemplate();
275
+ }
276
+
268
277
  if (this.props.location.query.type === 'embedded') {
269
278
  this.props.actions.resetAccount();
270
279
  }
@@ -594,7 +603,7 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
594
603
  }
595
604
  onCreateComplete = (isReloadTemplates) => {
596
605
  this.setState({routeParams: null, previewOpen: false}, () => {
597
- if (this.isFullMode() && isReloadTemplates) {
606
+ if (this.isFullMode() && (isReloadTemplates)) {
598
607
  this.getAllTemplates({params: {}}, true);
599
608
  }
600
609
  });
@@ -730,10 +739,16 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
730
739
  }
731
740
 
732
741
  isStatusMatching = (status, selectedWhatsappStatus) => {
733
- if ( [WHATSAPP_STATUSES.unsubmitted, WHATSAPP_STATUSES.pending].includes(status) ) {
734
- return selectedWhatsappStatus === WHATSAPP_STATUSES.awaitingApproval;
742
+ if(this.props.isFullMode && selectedWhatsappStatus) {
743
+ if ( [WHATSAPP_STATUSES.unsubmitted, WHATSAPP_STATUSES.pending].includes(status) ) {
744
+ return selectedWhatsappStatus === WHATSAPP_STATUSES.awaitingApproval;
745
+ }
746
+ return selectedWhatsappStatus === status;
747
+ }
748
+ else if (!this.props.isFullMode){
749
+ return status === WHATSAPP_STATUSES.approved;
735
750
  }
736
- return selectedWhatsappStatus === status;
751
+ return true;
737
752
  }
738
753
 
739
754
  filterWhatsappTemplates = (templates) => {
@@ -743,9 +758,7 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
743
758
 
744
759
  // if status or category filter is applied, filter templates which match these filters
745
760
  return (
746
- selectedWhatsappStatus
747
- ? this.isStatusMatching(status, selectedWhatsappStatus)
748
- : true
761
+ this.isStatusMatching(status, selectedWhatsappStatus)
749
762
  ) && (
750
763
  selectedWhatsappCategory
751
764
  ? category === selectedWhatsappCategory
@@ -1350,7 +1363,7 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
1350
1363
  } else {
1351
1364
  this.props.createNew();
1352
1365
  }
1353
- } else if (ev.key && (ev.key.toLowerCase() === "text" || ev.key.toLowerCase() === "image")) {
1366
+ } else if (ev?.key && (ev.key.toLowerCase() === "text" || ev.key.toLowerCase() === "image")) {
1354
1367
  routeParams = {
1355
1368
  pathname: `/${channel === 'line' ? 'line' : 'mobilepush'}/create/${ev.key.toLowerCase()}`,
1356
1369
  query: type === 'embedded' ? {type: 'embedded', module} : {module},
@@ -2249,6 +2262,9 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
2249
2262
  setLineFilter = (e) => this.setState({lineFilter: e.target.value});
2250
2263
  setSMSFilter = (e) => this.setState({smsFilter: e.target.value});
2251
2264
 
2265
+ openCreativesFullMode = () => {
2266
+ window.open(`/creatives/ui/v2?channel=${WHATSAPP_LOWERCASE}&mode=${CREATE}`, "_blank");
2267
+ }
2252
2268
 
2253
2269
  render() {
2254
2270
  const isFullMode = this.isFullMode();
@@ -2322,16 +2338,30 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
2322
2338
  const channelLowerCase = (channel || '').toLowerCase();
2323
2339
  const isTraiDltFeature = this.checkDLTfeatureEnable();
2324
2340
 
2325
- const createButton = (<CapButton
2326
- className={`create-new-${channelLowerCase}`}
2327
- type={"primary"}
2328
- disabled={this.isCreateDisabled()}
2329
- style={{marginLeft: '8px', marginBottom: '12px'}}
2330
- onClick={this.createTemplate} >
2331
- { this.props.intl.formatMessage((isTraiDltFeature && channel.toUpperCase() === SMS ) ? messages.uploadTemplate : messages.createNewActionButton) }
2332
- </CapButton>);
2341
+ const createButton =
2342
+ ( channelLowerCase === WHATSAPP_LOWERCASE && !this.props.isFullMode )
2343
+ ? (
2344
+ <CapLink
2345
+ onClick={this.openCreativesFullMode}
2346
+ title={formatMessage(messages.createNewTemplateLink)}
2347
+ suffix={<CapIcon type="open-in-new" size="s" />}
2348
+ className="create-new-link"
2349
+ />
2350
+ )
2351
+ : (
2352
+ <CapButton
2353
+ className={`create-new-${channelLowerCase}`}
2354
+ type={"primary"}
2355
+ disabled={this.isCreateDisabled()}
2356
+ style={{marginLeft: '8px', marginBottom: '12px'}}
2357
+ onClick={this.createTemplate}
2358
+ >
2359
+ { this.props.intl.formatMessage((isTraiDltFeature && channel.toUpperCase() === SMS ) ? messages.uploadTemplate : messages.createNewActionButton) }
2360
+ </CapButton>
2361
+ );
2333
2362
 
2334
2363
  const isWhatsappCountExeeded = templatesCount >= MAX_WHATSAPP_TEMPLATES;
2364
+ const showWhatsappCountWarning = templatesCount >= WARNING_WHATSAPP_TEMPLATES;
2335
2365
  const whatsappCountExceedText = <FormattedMessage {...messages.whatsappMaxTemplates} values={{ maxCount: MAX_WHATSAPP_TEMPLATES }}/>;
2336
2366
 
2337
2367
  const filterContent = (( isfilterContentVisisble || [WECHAT, MOBILE_PUSH].includes(this.state.channel.toUpperCase())) && <div className="action-container">
@@ -2361,16 +2391,19 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
2361
2391
  {
2362
2392
  channel.toUpperCase() === WHATSAPP && (
2363
2393
  <div className="whatsapp-filters">
2364
- <CapSelectFilter
2365
- placement="bottomLeft"
2366
- data={STATUS_OPTIONS}
2367
- onSelect={this.setWhatsappStatus}
2368
- selectedValue={this.state.selectedWhatsappStatus}
2369
- placeholder="Status"
2370
- showBadge={true}
2371
- width="90px"
2372
- overlayStyle={{ overflowY: "hidden" }}
2373
- />
2394
+ {
2395
+ this.props.isFullMode ? (
2396
+ <CapSelectFilter
2397
+ placement="bottomLeft"
2398
+ data={STATUS_OPTIONS}
2399
+ onSelect={this.setWhatsappStatus}
2400
+ selectedValue={this.state.selectedWhatsappStatus}
2401
+ placeholder="Status"
2402
+ showBadge={true}
2403
+ width="90px"
2404
+ />
2405
+ ) : null
2406
+ }
2374
2407
  <CapSelectFilter
2375
2408
  placement="bottomLeft"
2376
2409
  data={CATEGORY_OPTIONS}
@@ -2496,7 +2529,7 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
2496
2529
  <input type="file" id="filename" style={{ display: 'none'}} accept=".zip, .html, .htm" onChange={(event) => this.handleFileUpload(event, {files: event.target.files})} />
2497
2530
 
2498
2531
  {
2499
- channel.toLowerCase() === WHATSAPP_LOWERCASE && isWhatsappCountExeeded ? (
2532
+ channel.toLowerCase() === WHATSAPP_LOWERCASE && showWhatsappCountWarning ? (
2500
2533
  <CapAlert message={whatsappCountExceedText} type="info" />
2501
2534
  ) : null
2502
2535
  }
@@ -2507,6 +2540,11 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
2507
2540
  </Pagination>
2508
2541
  {(((this.state.selectedAccount !== '' && !isEmpty(this.props.Templates.selectedWeChatAccount) && this.state.channel.toLowerCase() === 'wechat') || this.state.channel.toLowerCase() !== 'wechat') && isEmpty(this.props.TemplatesList)) && !this.props.Templates.getAllTemplatesInProgress && !isEmpty(this.state.searchText) &&
2509
2542
  <div style={{ height: '65vh', textAlign: 'center', lineHeight: '65vh'}}>
2543
+ {
2544
+ channel.toLowerCase() === WHATSAPP_LOWERCASE ? (
2545
+ <CapAlert message={whatsappCountExceedText} type="info" />
2546
+ ) : null
2547
+ }
2510
2548
  <CapHeading type="h6">{this.props.intl.formatMessage(messages.noTemplatesFound)}</CapHeading>
2511
2549
  </div>}
2512
2550
  </CapRow>
@@ -274,6 +274,10 @@ export default defineMessages({
274
274
  id: `${scope}.createNewActionButton`,
275
275
  defaultMessage: `Create new`,
276
276
  },
277
+ "createNewTemplateLink": {
278
+ id: `${scope}.createNewTemplateLink`,
279
+ defaultMessage: `Create new template`,
280
+ },
277
281
  "creativeTemplates": {
278
282
  id: `${scope}.creativeTemplates`,
279
283
  defaultMessage: `Creative templates`,
@@ -31,6 +31,7 @@ import withStyles from '../../hoc/withStyles';
31
31
  import styles, { CapTabStyle } from './TemplatesV2.style';
32
32
  import { CREATIVES_UI_VIEW, LOYALTY} from '../App/constants';
33
33
  import AccessForbidden from '../../v2Components/AccessForbidden';
34
+ import { getObjFromQueryParams } from '../../utils/v2common';
34
35
 
35
36
  const {CapCustomCardList} = CapCustomCard;
36
37
 
@@ -50,7 +51,7 @@ export class TemplatesV2 extends React.Component { // eslint-disable-line react/
50
51
  isFullMode,
51
52
  onChannelChange,
52
53
  showDisabledFBInfo,
53
- enableNewChannels = [],
54
+ enableNewChannels,
54
55
  } = props;
55
56
 
56
57
  const defaultPanes = {
@@ -124,6 +125,16 @@ export class TemplatesV2 extends React.Component { // eslint-disable-line react/
124
125
  onChannelChange(defaultChannel);
125
126
  }
126
127
  }
128
+
129
+ componentDidMount() {
130
+ const queryItems = getObjFromQueryParams(location.search);
131
+
132
+ if(queryItems.channel === 'whatsapp') {
133
+ console.log("reached whatsapp content");
134
+ this.channelChange('whatsapp');
135
+ }
136
+ }
137
+
127
138
  componentWillReceiveProps(nextProps) {
128
139
  if (this.props.channel !== nextProps.channel) {
129
140
  const panes = this.setChannelContent(nextProps.channel, this.state.panes);
@@ -52,9 +52,11 @@ import withCreatives from '../../hoc/withCreatives';
52
52
  import TemplatePreview from '../../v2Components/TemplatePreview';
53
53
  import TagList from '../TagList';
54
54
  import { makeSelectMetaEntities, setInjectedTags } from '../Cap/selectors';
55
+ import { validateTags } from '../../utils/tagValidations';
55
56
 
56
57
  let varMap = {};
57
58
  let editContent = {};
59
+ let tagValidationResponse = {};
58
60
 
59
61
  export const Whatsapp = (props) => {
60
62
  const {
@@ -74,6 +76,7 @@ export const Whatsapp = (props) => {
74
76
  metaEntities,
75
77
  injectedTags,
76
78
  loadingTags,
79
+ getFormData
77
80
  } = props || {};
78
81
  const { formatMessage } = intl;
79
82
  const { TextArea } = CapInput;
@@ -99,6 +102,7 @@ export const Whatsapp = (props) => {
99
102
  //for tag only
100
103
  const [tags, updateTags] = useState([]);
101
104
  const [textAreaId, updateTextAreaId] = useState();
105
+ const [isTagValidationError, updateIsTagValidationError] = useState(false);
102
106
 
103
107
  const validVarRegex = /{{([1-9]|1[0-9])}}/g;
104
108
 
@@ -109,7 +113,8 @@ export const Whatsapp = (props) => {
109
113
  width: 100%;
110
114
  margin-left: -32px;
111
115
  padding: ${CAP_SPACE_32} ${CAP_SPACE_24};
112
-
116
+ z-index: 1;
117
+
113
118
  .ant-btn {
114
119
  margin-right: ${CAP_SPACE_16};
115
120
  }
@@ -141,7 +146,6 @@ export const Whatsapp = (props) => {
141
146
  setSpin(true);
142
147
  actions.getTemplateDetails(id);
143
148
  }
144
- setEditFlow(true);
145
149
  }
146
150
  //cleanup code
147
151
  return () => {
@@ -155,9 +159,10 @@ export const Whatsapp = (props) => {
155
159
  name = '',
156
160
  versions = {},
157
161
  createdAt = '',
158
- } = editData.templateDetails || templateData || {};
162
+ } = isFullMode ? editData.templateDetails || {} : templateData || {};
159
163
  editContent = get(versions, `base.content.whatsapp`, {});
160
164
  if (editContent && !isEmpty(editContent)) {
165
+ setEditFlow(true);
161
166
  setTemplateName(name);
162
167
  setTemplateDate(createdAt);
163
168
  const {
@@ -261,6 +266,27 @@ export const Whatsapp = (props) => {
261
266
  }
262
267
  }, [metaEntities, isEditFlow]);
263
268
 
269
+ //performs tag validation
270
+ useEffect(() => {
271
+ if (
272
+ !isFullMode &&
273
+ updatedSmsEditor?.length > 0 &&
274
+ !updatedSmsEditor.join('').match(validVarRegex)
275
+ ) {
276
+ tagValidationResponse =
277
+ validateTags({
278
+ content: updatedSmsEditor.join(''),
279
+ tagsParam: tags,
280
+ injectedTagsParams: injectedTags,
281
+ location,
282
+ tagModule: getDefaultTags,
283
+ }) || {};
284
+ updateIsTagValidationError(
285
+ tagValidationResponse.unsupportedTags.length > 0,
286
+ );
287
+ }
288
+ }, [updatedSmsEditor, tags]);
289
+
264
290
  const handleOnTagsContextChange = (data) => {
265
291
  const { type } = location.query || {};
266
292
  const isEmbedded = type === EMBEDDED;
@@ -468,13 +494,16 @@ export const Whatsapp = (props) => {
468
494
  languages: [
469
495
  {
470
496
  language: 'en',
471
- content: `$'${templateMessage}\nClick {{${
472
- addedVarCount + 1
473
- }}} to unsubscribe'`,
497
+ content:
498
+ isEditFlow
499
+ ? `${updatedSmsEditor.join('')} ${formatMessage(messages.templateMessageUnsubscribeText)}`
500
+ : `$'${templateMessage}\nClick {{${
501
+ addedVarCount + 1 }}} to unsubscribe'`,
474
502
  },
475
503
  ],
476
- mediaType: 'text',
477
- varMapped: {},
504
+ mediaType: 'TEXT',
505
+ varMapped: varMap,
506
+ templateEditor: tempMsgArray.join(''),
478
507
  accountId,
479
508
  accessToken,
480
509
  accountName,
@@ -519,6 +548,15 @@ export const Whatsapp = (props) => {
519
548
  }
520
549
  };
521
550
 
551
+ const saveToMessage = () => {
552
+ getFormData({
553
+ value: createPayload(),
554
+ _id: params?.id,
555
+ validity: true,
556
+ type: 'WHATSAPP',
557
+ });
558
+ }
559
+
522
560
  const isDisableDone = () => {
523
561
  //if template name is not entered
524
562
  if (templateName.trim() === '' || templateNameError) {
@@ -774,6 +812,16 @@ export const Whatsapp = (props) => {
774
812
  }
775
813
  };
776
814
 
815
+ const tagValidationErrorMessage = () => {
816
+ const { unsupportedTags = [] } = tagValidationResponse;
817
+ let tagError = '';
818
+ if (unsupportedTags.length > 0) {
819
+ tagError = formatMessage(messages.unsupportedTagsValidationError, {
820
+ unsupportedTags,
821
+ });
822
+ }
823
+ return <CapError>{tagError}</CapError>;
824
+ };
777
825
  const editModeContent = (
778
826
  <>
779
827
  {templateStatus && (
@@ -815,6 +863,7 @@ export const Whatsapp = (props) => {
815
863
  </CapTooltip>
816
864
 
817
865
  {renderMessageLength()}
866
+ {isTagValidationError && tagValidationErrorMessage()}
818
867
  </>
819
868
  );
820
869
  //edit methods end
@@ -841,6 +890,13 @@ export const Whatsapp = (props) => {
841
890
  );
842
891
  };
843
892
 
893
+ const isEditDoneDisabled = () => {
894
+ return isTagValidationError || Object.values(varMap).some( (inputValue) => {
895
+ if (inputValue === '') {
896
+ return true;
897
+ }
898
+ });
899
+ }
844
900
  return (
845
901
  <CapSpin spinning={spin}>
846
902
  <CapRow className='cap-whatsapp-creatives'>
@@ -875,6 +931,17 @@ export const Whatsapp = (props) => {
875
931
  </CapButton>
876
932
  </>
877
933
  )}
934
+ {!isFullMode && isEditFlow && (
935
+ <>
936
+ <CapButton
937
+ onClick={saveToMessage}
938
+ disabled={isEditDoneDisabled()}
939
+ className="whatsapp-create-btn"
940
+ >
941
+ <FormattedMessage {...messages.done} />
942
+ </CapButton>
943
+ </>
944
+ )}
878
945
  </WhatsappFooter>
879
946
  </CapSpin>
880
947
  );
@@ -1,4 +1,3 @@
1
- import React from 'react';
2
1
  import { WHATSAPP } from '../CreativesContainer/constants';
3
2
  import {
4
3
  STATUS_OPTIONS,