@capillarytech/creatives-library 7.10.39 → 7.10.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/containers/Assets/Gallery/tests/__snapshots__/reducer.test.js.snap +0 -2
- package/containers/Email/index.js +2 -3
- package/index.js +6 -0
- package/package.json +1 -1
- package/routes.js +5 -0
- package/services/api.js +6 -1
- package/v2Components/TemplatePreview/_templatePreview.scss +7 -0
- package/v2Components/TemplatePreview/assets/images/whatsapp_mobile_android.svg +2041 -0
- package/v2Components/TemplatePreview/index.js +57 -3
- package/v2Components/TemplatePreview/messages.js +8 -0
- package/v2Containers/Assets/Gallery/tests/__snapshots__/reducer.test.js.snap +0 -2
- package/v2Containers/Assets/images/whatsappIllustration.png +0 -0
- package/v2Containers/CreativesContainer/SlideBoxContent.js +31 -2
- package/v2Containers/CreativesContainer/SlideBoxHeader.js +31 -3
- package/v2Containers/CreativesContainer/constants.js +1 -0
- package/v2Containers/CreativesContainer/messages.js +4 -0
- package/v2Containers/Email/index.js +1 -3
- package/v2Containers/Line/Container/index.js +1 -1
- package/v2Containers/Templates/_templates.scss +43 -0
- package/v2Containers/Templates/actions.js +18 -10
- package/v2Containers/Templates/constants.js +3 -1
- package/v2Containers/Templates/index.js +296 -44
- package/v2Containers/Templates/messages.js +32 -0
- package/v2Containers/Templates/reducer.js +3 -1
- package/v2Containers/TemplatesV2/index.js +2 -0
- package/v2Containers/TemplatesV2/messages.js +4 -0
- package/v2Containers/Whatsapp/actions.js +34 -0
- package/v2Containers/Whatsapp/constants.js +125 -0
- package/v2Containers/Whatsapp/index.js +831 -0
- package/v2Containers/Whatsapp/index.scss +56 -0
- package/v2Containers/Whatsapp/messages.js +221 -0
- package/v2Containers/Whatsapp/reducer.js +54 -0
- package/v2Containers/Whatsapp/sagas.js +77 -0
- package/v2Containers/Whatsapp/selectors.js +12 -0
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +120831 -0
- package/v2Containers/Whatsapp/tests/index.test.js +132 -0
- package/v2Containers/Whatsapp/tests/mockData.js +10 -0
- package/v2Containers/Whatsapp/utils.js +106 -0
|
@@ -0,0 +1,831 @@
|
|
|
1
|
+
/* eslint-disable no-undef */
|
|
2
|
+
import React, { useState, useEffect } from 'react';
|
|
3
|
+
import { bindActionCreators } from 'redux';
|
|
4
|
+
import { createStructuredSelector } from 'reselect';
|
|
5
|
+
import { injectIntl, FormattedMessage } from 'react-intl';
|
|
6
|
+
import { get, isEmpty, cloneDeep } from 'lodash';
|
|
7
|
+
import styled from 'styled-components';
|
|
8
|
+
import CapSpin from '@capillarytech/cap-ui-library/CapSpin';
|
|
9
|
+
import CapRow from '@capillarytech/cap-ui-library/CapRow';
|
|
10
|
+
import CapColumn from '@capillarytech/cap-ui-library/CapColumn';
|
|
11
|
+
import CapHeader from '@capillarytech/cap-ui-library/CapHeader';
|
|
12
|
+
import CapTooltipWithInfo from '@capillarytech/cap-ui-library/CapTooltipWithInfo';
|
|
13
|
+
import CapInput from '@capillarytech/cap-ui-library/CapInput';
|
|
14
|
+
import CapSelect from '@capillarytech/cap-ui-library/CapSelect';
|
|
15
|
+
import CapHeading from '@capillarytech/cap-ui-library/CapHeading';
|
|
16
|
+
import CapRadioGroup from '@capillarytech/cap-ui-library/CapRadioGroup';
|
|
17
|
+
import CapTooltip from '@capillarytech/cap-ui-library/CapTooltip';
|
|
18
|
+
import CapError from '@capillarytech/cap-ui-library/CapError';
|
|
19
|
+
import CapLabel from '@capillarytech/cap-ui-library/CapLabel';
|
|
20
|
+
import CapButton from '@capillarytech/cap-ui-library/CapButton';
|
|
21
|
+
import CapNotification from '@capillarytech/cap-ui-library/CapNotification';
|
|
22
|
+
import CapAlert from '@capillarytech/cap-ui-library/CapAlert';
|
|
23
|
+
import moment from 'moment';
|
|
24
|
+
import {
|
|
25
|
+
CAP_SPACE_04,
|
|
26
|
+
CAP_SPACE_16,
|
|
27
|
+
CAP_SPACE_24,
|
|
28
|
+
CAP_SPACE_32,
|
|
29
|
+
CAP_WHITE,
|
|
30
|
+
} from '@capillarytech/cap-ui-library/styled/variables';
|
|
31
|
+
import { makeSelectWhatsapp, makeSelectAccount } from './selectors';
|
|
32
|
+
import * as WhatsappActions from './actions';
|
|
33
|
+
import './index.scss';
|
|
34
|
+
import {
|
|
35
|
+
UNSUBSCRIBE_TEXT_LENGTH,
|
|
36
|
+
TEMPLATE_MESSAGE_MAX_LENGTH,
|
|
37
|
+
WHATSAPP,
|
|
38
|
+
CATEGORY_OPTIONS,
|
|
39
|
+
WHATSAPP_STATUSES,
|
|
40
|
+
TAG,
|
|
41
|
+
EMBEDDED,
|
|
42
|
+
DEFAULT,
|
|
43
|
+
FULL,
|
|
44
|
+
ALL,
|
|
45
|
+
LIBRARY,
|
|
46
|
+
} from './constants';
|
|
47
|
+
import messages from './messages';
|
|
48
|
+
import withCreatives from '../../hoc/withCreatives';
|
|
49
|
+
import TemplatePreview from '../../v2Components/TemplatePreview';
|
|
50
|
+
import TagList from '../TagList';
|
|
51
|
+
import { makeSelectMetaEntities, setInjectedTags } from '../Cap/selectors';
|
|
52
|
+
|
|
53
|
+
let varMap = {};
|
|
54
|
+
let editContent = {};
|
|
55
|
+
|
|
56
|
+
export const Whatsapp = (props) => {
|
|
57
|
+
const {
|
|
58
|
+
intl,
|
|
59
|
+
actions,
|
|
60
|
+
isFullMode,
|
|
61
|
+
onCreateComplete,
|
|
62
|
+
handleClose,
|
|
63
|
+
params,
|
|
64
|
+
templateData = {},
|
|
65
|
+
editData = {},
|
|
66
|
+
accountData = {},
|
|
67
|
+
globalActions,
|
|
68
|
+
location,
|
|
69
|
+
getDefaultTags,
|
|
70
|
+
supportedTags,
|
|
71
|
+
metaEntities,
|
|
72
|
+
injectedTags,
|
|
73
|
+
} = props || {};
|
|
74
|
+
const { formatMessage } = intl;
|
|
75
|
+
const { TextArea } = CapInput;
|
|
76
|
+
const [templateName, setTemplateName] = useState('');
|
|
77
|
+
const [templateNameError, setTemplateNameError] = useState(false);
|
|
78
|
+
const [templateCategory, setTemplateCategory] = useState(
|
|
79
|
+
formatMessage(messages.select),
|
|
80
|
+
);
|
|
81
|
+
const [templateMessage, setTemplateMessage] = useState('');
|
|
82
|
+
const [templateMessageError, setTemplateMessageError] = useState(false);
|
|
83
|
+
const [addedVarCount, setAddedVarCount] = useState(0);
|
|
84
|
+
const [accountId, setAccountId] = useState('');
|
|
85
|
+
const [accessToken, setAccessToken] = useState('');
|
|
86
|
+
const [accountName, setAccountName] = useState('');
|
|
87
|
+
const [spin, setSpin] = useState(false);
|
|
88
|
+
//for edit only
|
|
89
|
+
const [isEditFlow, setEditFlow] = useState(false);
|
|
90
|
+
const [templateDate, setTemplateDate] = useState('');
|
|
91
|
+
const [templateStatus, setTemplateStatus] = useState(
|
|
92
|
+
WHATSAPP_STATUSES.unsubmitted,
|
|
93
|
+
);
|
|
94
|
+
const [tempMsgArray, updateTempMsgArray] = useState([]);
|
|
95
|
+
const [updatedSmsEditor, setUpdatedSmsEditor] = useState([]);
|
|
96
|
+
//for tag only
|
|
97
|
+
const [tags, updateTags] = useState([]);
|
|
98
|
+
const [textAreaId, updateTextAreaId] = useState();
|
|
99
|
+
|
|
100
|
+
const validVarRegex = /{{([1-9]|1[0-9])}}/g;
|
|
101
|
+
|
|
102
|
+
const WhatsappFooter = styled.div`
|
|
103
|
+
background-color: ${CAP_WHITE};
|
|
104
|
+
position: fixed;
|
|
105
|
+
bottom: 0;
|
|
106
|
+
width: 100%;
|
|
107
|
+
margin-left: -32px;
|
|
108
|
+
padding: ${CAP_SPACE_32} ${CAP_SPACE_24};
|
|
109
|
+
|
|
110
|
+
.ant-btn {
|
|
111
|
+
margin-right: ${CAP_SPACE_16};
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
`;
|
|
115
|
+
//edit
|
|
116
|
+
//gets account details
|
|
117
|
+
useEffect(() => {
|
|
118
|
+
const accountObj = accountData.selectedWhatsappAccount || {};
|
|
119
|
+
if (!isEmpty(accountObj)) {
|
|
120
|
+
setAccountId(get(accountObj, `sourceAccountIdentifier`, ''));
|
|
121
|
+
setAccessToken(get(accountObj, `configs.accessToken`, ''));
|
|
122
|
+
setAccountName(get(accountObj, `name`, ''));
|
|
123
|
+
}
|
|
124
|
+
}, [accountData.selectedWhatsappAccount]);
|
|
125
|
+
|
|
126
|
+
//gets template details
|
|
127
|
+
const paramObj = params || {};
|
|
128
|
+
useEffect(() => {
|
|
129
|
+
const { id } = paramObj;
|
|
130
|
+
if (id && !get(templateData, `versions.base.content`)) {
|
|
131
|
+
setSpin(true);
|
|
132
|
+
actions.getTemplateDetails(id);
|
|
133
|
+
setEditFlow(true);
|
|
134
|
+
}
|
|
135
|
+
//cleanup code
|
|
136
|
+
return () => {
|
|
137
|
+
actions.resetEditTemplate();
|
|
138
|
+
varMap = {};
|
|
139
|
+
};
|
|
140
|
+
}, [paramObj.id]);
|
|
141
|
+
|
|
142
|
+
useEffect(() => {
|
|
143
|
+
editContent =
|
|
144
|
+
get(templateData, `versions.base.content.whatsapp`) ||
|
|
145
|
+
get(editData, `templateDetails.versions.base.content.whatsapp`) ||
|
|
146
|
+
{};
|
|
147
|
+
if (editContent && !isEmpty(editContent)) {
|
|
148
|
+
const editMessageTitle =
|
|
149
|
+
(templateData || {}).name || get(editData, 'templateDetails.name');
|
|
150
|
+
const createdAt =
|
|
151
|
+
(templateData || {}).createdAt ||
|
|
152
|
+
get(editData, 'templateDetails.createdAt');
|
|
153
|
+
setTemplateName(editMessageTitle);
|
|
154
|
+
setTemplateDate(createdAt);
|
|
155
|
+
setTemplateCategory(get(editContent, `category`, ''));
|
|
156
|
+
setTemplateStatus(
|
|
157
|
+
get(editContent, `status`, WHATSAPP_STATUSES.unsubmitted),
|
|
158
|
+
);
|
|
159
|
+
computeTempMsgArray();
|
|
160
|
+
}
|
|
161
|
+
}, [editData.templateDetails || templateData]);
|
|
162
|
+
|
|
163
|
+
const computeTempMsgArray = () => {
|
|
164
|
+
let msg = get(editContent, `languages[0].content`, '');
|
|
165
|
+
const validVarArr = msg.match(validVarRegex) || [];
|
|
166
|
+
const templateMessageArray = [];
|
|
167
|
+
msg = msg.slice(2, -1);
|
|
168
|
+
msg = msg.replace(
|
|
169
|
+
`Click ${validVarArr[validVarArr.length - 1]} to unsubscribe`,
|
|
170
|
+
'',
|
|
171
|
+
);
|
|
172
|
+
validVarArr.pop();
|
|
173
|
+
while (msg.length !== 0) {
|
|
174
|
+
const index = msg.indexOf(validVarArr[0]);
|
|
175
|
+
if (index !== -1) {
|
|
176
|
+
templateMessageArray.push(msg.substring(0, index));
|
|
177
|
+
templateMessageArray.push(validVarArr[0]);
|
|
178
|
+
msg = msg.substring(index + validVarArr[0].length, msg.length);
|
|
179
|
+
validVarArr.shift();
|
|
180
|
+
} else {
|
|
181
|
+
templateMessageArray.push(msg);
|
|
182
|
+
break;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
updateTempMsgArray(templateMessageArray.filter((i) => i === 0 || i));
|
|
186
|
+
//stop spinner
|
|
187
|
+
setSpin(false);
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
useEffect(() => {
|
|
191
|
+
if (tempMsgArray.length !== 0) {
|
|
192
|
+
const { varMapped = {} } = editContent;
|
|
193
|
+
if (!isEmpty(varMapped)) {
|
|
194
|
+
varMap = cloneDeep(varMapped);
|
|
195
|
+
} else {
|
|
196
|
+
//computing and setting varMap for first edit
|
|
197
|
+
for (let i = 0; i < tempMsgArray.length; i += 1) {
|
|
198
|
+
if (tempMsgArray[i].match(validVarRegex)?.length > 0) {
|
|
199
|
+
varMap[`${tempMsgArray[i]}_${i}`] = '';
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
//setting updatedSmsEditor based on varMap
|
|
204
|
+
const arr = [...tempMsgArray];
|
|
205
|
+
for (const key in varMap) {
|
|
206
|
+
if (varMap[key] !== '') {
|
|
207
|
+
arr[key.slice(key.indexOf('_') + 1)] = varMap[key];
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
setUpdatedSmsEditor(arr);
|
|
211
|
+
}
|
|
212
|
+
}, [tempMsgArray]);
|
|
213
|
+
|
|
214
|
+
// tag Code start from here
|
|
215
|
+
useEffect(() => {
|
|
216
|
+
//fetching tags
|
|
217
|
+
const { type, module } = location.query || {};
|
|
218
|
+
const isEmbedded = type === EMBEDDED;
|
|
219
|
+
const query = {
|
|
220
|
+
layout: 'SMS',
|
|
221
|
+
type: TAG,
|
|
222
|
+
context: isEmbedded ? module : DEFAULT,
|
|
223
|
+
embedded: isEmbedded ? type : FULL,
|
|
224
|
+
};
|
|
225
|
+
if (getDefaultTags) {
|
|
226
|
+
query.context = getDefaultTags;
|
|
227
|
+
}
|
|
228
|
+
globalActions.fetchSchemaForEntity(query);
|
|
229
|
+
}, []);
|
|
230
|
+
|
|
231
|
+
useEffect(() => {
|
|
232
|
+
let tag =
|
|
233
|
+
metaEntities && metaEntities.tags ? metaEntities.tags.standard : [];
|
|
234
|
+
const { type, module } = location.query || {};
|
|
235
|
+
if (type === EMBEDDED && module === LIBRARY && !getDefaultTags) {
|
|
236
|
+
tag = supportedTags;
|
|
237
|
+
}
|
|
238
|
+
updateTags(tag);
|
|
239
|
+
}, [metaEntities]);
|
|
240
|
+
|
|
241
|
+
const handleOnTagsContextChange = (data) => {
|
|
242
|
+
const { type } = location.query || {};
|
|
243
|
+
const isEmbedded = type === EMBEDDED;
|
|
244
|
+
const query = {
|
|
245
|
+
layout: 'SMS',
|
|
246
|
+
type: TAG,
|
|
247
|
+
context:
|
|
248
|
+
(data || '').toLowerCase() === ALL
|
|
249
|
+
? DEFAULT
|
|
250
|
+
: (data || '').toLowerCase(),
|
|
251
|
+
embedded: isEmbedded ? type : FULL,
|
|
252
|
+
};
|
|
253
|
+
globalActions.fetchSchemaForEntity(query);
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
const onTagSelect = (data) => {
|
|
257
|
+
if (varMap && updatedSmsEditor) {
|
|
258
|
+
let numId = Number(textAreaId?.slice(textAreaId?.indexOf('_') + 1));
|
|
259
|
+
if (numId !== NaN) {
|
|
260
|
+
const arr = [...updatedSmsEditor];
|
|
261
|
+
//when trying to insert tag in empty textarea,{#var#} is replaced with "" and then tag is added
|
|
262
|
+
if (arr[numId]?.match(validVarRegex)?.length > 0) {
|
|
263
|
+
arr[numId] = '';
|
|
264
|
+
}
|
|
265
|
+
const messageData = `${arr[numId]}{{${data}}}`;
|
|
266
|
+
arr[numId] = messageData;
|
|
267
|
+
varMap[textAreaId] = messageData;
|
|
268
|
+
setUpdatedSmsEditor(arr);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
//setting the id of currently selected text area, is used onTagSelect
|
|
274
|
+
const setTextAreaId = ({ target: { id } }) => {
|
|
275
|
+
updateTextAreaId(id);
|
|
276
|
+
};
|
|
277
|
+
// tag Code end
|
|
278
|
+
|
|
279
|
+
//create methods start
|
|
280
|
+
const renderTemplateCategoryLabel = (tooltipLabel, title) => (
|
|
281
|
+
<CapRow>
|
|
282
|
+
<CapColumn span={23}>{title}</CapColumn>
|
|
283
|
+
<CapColumn span={1}>
|
|
284
|
+
<CapTooltipWithInfo
|
|
285
|
+
infoIconProps={{
|
|
286
|
+
style: { marginLeft: CAP_SPACE_16 },
|
|
287
|
+
}}
|
|
288
|
+
autoAdjustOverflow
|
|
289
|
+
placement="right"
|
|
290
|
+
title={tooltipLabel}
|
|
291
|
+
/>
|
|
292
|
+
</CapColumn>
|
|
293
|
+
</CapRow>
|
|
294
|
+
);
|
|
295
|
+
|
|
296
|
+
const templateCategoryOptions = CATEGORY_OPTIONS.map((option) => ({
|
|
297
|
+
value: option.value,
|
|
298
|
+
label: renderTemplateCategoryLabel(option.tooltipLabel, option.label),
|
|
299
|
+
}));
|
|
300
|
+
|
|
301
|
+
const mediaRadioOptions = [
|
|
302
|
+
{
|
|
303
|
+
value: 'text',
|
|
304
|
+
label: formatMessage(messages.mediaTextMessage),
|
|
305
|
+
},
|
|
306
|
+
{
|
|
307
|
+
value: 'image',
|
|
308
|
+
label: (
|
|
309
|
+
<CapTooltip title={formatMessage(messages.disabledMediaTooltip)}>
|
|
310
|
+
{formatMessage(messages.mediaImage)}
|
|
311
|
+
</CapTooltip>
|
|
312
|
+
),
|
|
313
|
+
disabled: true,
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
value: 'video',
|
|
317
|
+
label: (
|
|
318
|
+
<CapTooltip title={formatMessage(messages.disabledMediaTooltip)}>
|
|
319
|
+
{formatMessage(messages.mediaVideo)}
|
|
320
|
+
</CapTooltip>
|
|
321
|
+
),
|
|
322
|
+
disabled: true,
|
|
323
|
+
},
|
|
324
|
+
];
|
|
325
|
+
|
|
326
|
+
const renderLabel = (value) => (
|
|
327
|
+
<CapHeading type="h4" className="whatsapp-render-heading">
|
|
328
|
+
{formatMessage(messages[value])}
|
|
329
|
+
</CapHeading>
|
|
330
|
+
);
|
|
331
|
+
|
|
332
|
+
const renderUnsubscribeText = () => (
|
|
333
|
+
<>
|
|
334
|
+
<CapColumn span={12}>
|
|
335
|
+
<CapTooltip
|
|
336
|
+
placement="bottom"
|
|
337
|
+
title={formatMessage(messages.unsubscribeTextTooltip)}
|
|
338
|
+
>
|
|
339
|
+
<CapHeading
|
|
340
|
+
className={
|
|
341
|
+
!isEditFlow
|
|
342
|
+
? 'whatsapp-create-render-unsubscribe-text'
|
|
343
|
+
: 'whatsapp-edit-render-unsubscribe-text'
|
|
344
|
+
}
|
|
345
|
+
>
|
|
346
|
+
{formatMessage(messages.templateMessageUnsubscribeText)}
|
|
347
|
+
</CapHeading>
|
|
348
|
+
</CapTooltip>
|
|
349
|
+
</CapColumn>
|
|
350
|
+
<CapColumn span={12}></CapColumn>
|
|
351
|
+
</>
|
|
352
|
+
);
|
|
353
|
+
|
|
354
|
+
const renderMessageLength = () => (
|
|
355
|
+
<CapHeading type="h6" className="whatsapp-render-message-length">
|
|
356
|
+
{formatMessage(messages.templateMessageLength, {
|
|
357
|
+
currentLength: UNSUBSCRIBE_TEXT_LENGTH + templateMessage?.length,
|
|
358
|
+
maxLength: TEMPLATE_MESSAGE_MAX_LENGTH,
|
|
359
|
+
})}
|
|
360
|
+
</CapHeading>
|
|
361
|
+
);
|
|
362
|
+
|
|
363
|
+
const onTemplateNameChange = ({ target: { value } }) => {
|
|
364
|
+
setTemplateName(value);
|
|
365
|
+
templateNameErrorHandler(value);
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
const templateNameErrorHandler = (value) => {
|
|
369
|
+
let errorMessage = false;
|
|
370
|
+
//regex to accept only lowercase alphanumeric characters and underscores
|
|
371
|
+
const templateNameRegex = /^[a-z0-9_]+$/;
|
|
372
|
+
if (value === '') {
|
|
373
|
+
errorMessage = formatMessage(messages.emptyTemplateNameErrorMessage);
|
|
374
|
+
} else if (!templateNameRegex.test(value)) {
|
|
375
|
+
errorMessage = formatMessage(messages.templateNameRegexErrorMessage);
|
|
376
|
+
}
|
|
377
|
+
setTemplateNameError(errorMessage);
|
|
378
|
+
};
|
|
379
|
+
|
|
380
|
+
const onTemplateCategoryChange = (value) => {
|
|
381
|
+
setTemplateCategory(value);
|
|
382
|
+
};
|
|
383
|
+
|
|
384
|
+
const onTemplateMessageChange = ({ target: { value } }) => {
|
|
385
|
+
const error = templateMessageErrorHandler(value);
|
|
386
|
+
setTemplateMessage(value);
|
|
387
|
+
setTemplateMessageError(error);
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
const templateMessageErrorHandler = (value) => {
|
|
391
|
+
let errorMessage = false;
|
|
392
|
+
if (value === '') {
|
|
393
|
+
errorMessage = formatMessage(messages.emptyTemplateMessageErrorMessage);
|
|
394
|
+
} else if (
|
|
395
|
+
UNSUBSCRIBE_TEXT_LENGTH + value?.length >
|
|
396
|
+
TEMPLATE_MESSAGE_MAX_LENGTH
|
|
397
|
+
) {
|
|
398
|
+
errorMessage = formatMessage(messages.templateMessageLengthError);
|
|
399
|
+
} else {
|
|
400
|
+
const validVarArr = value.match(validVarRegex) || [];
|
|
401
|
+
const validVarSet = [...new Set(validVarArr)];
|
|
402
|
+
|
|
403
|
+
const invalidVarRegex = /{{(.+?)}}/g;
|
|
404
|
+
const invalidVarArr = value.match(invalidVarRegex) || [];
|
|
405
|
+
const invalidVarSet = [...new Set(invalidVarArr)];
|
|
406
|
+
|
|
407
|
+
const noContentBetweenVars = /}}[^a-zA-Z]*{{/g;
|
|
408
|
+
|
|
409
|
+
if (validVarArr?.length > 0 || invalidVarArr?.length > 0) {
|
|
410
|
+
if (validVarArr?.length !== validVarSet?.length) {
|
|
411
|
+
//checks for repetations like Hi {{1}}, offer for you {{1}}
|
|
412
|
+
errorMessage = formatMessage(messages.repetativeVars);
|
|
413
|
+
} else if (invalidVarSet?.length !== validVarSet?.length) {
|
|
414
|
+
//checks for invalid vars like Hi {{abcd}}, offer for you {{^_^}}
|
|
415
|
+
errorMessage = formatMessage(messages.unknownVars);
|
|
416
|
+
} else if (value.match(noContentBetweenVars)?.length > 0) {
|
|
417
|
+
//checks for text between vars like Hi {{1}}{{2}}
|
|
418
|
+
errorMessage = formatMessage(messages.noContentBetweenVars);
|
|
419
|
+
} else {
|
|
420
|
+
//checks if vars are added sequentially like, Hi {{1}}, offer for you {{2}} today {{3}}
|
|
421
|
+
const checkSequence = [...validVarSet].filter(
|
|
422
|
+
(validVar, index) => `{{${index + 1}}}` !== validVar,
|
|
423
|
+
);
|
|
424
|
+
if (checkSequence?.length > 0) {
|
|
425
|
+
errorMessage = formatMessage(messages.sequenceVars);
|
|
426
|
+
} else {
|
|
427
|
+
setAddedVarCount(validVarSet?.length || 0);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
return errorMessage;
|
|
433
|
+
};
|
|
434
|
+
|
|
435
|
+
const createPayload = () => ({
|
|
436
|
+
name: templateName,
|
|
437
|
+
versions: {
|
|
438
|
+
base: {
|
|
439
|
+
content: {
|
|
440
|
+
whatsapp: {
|
|
441
|
+
category: templateCategory,
|
|
442
|
+
languages: [
|
|
443
|
+
{
|
|
444
|
+
language: 'en',
|
|
445
|
+
content: `$'${templateMessage}\nClick {{${
|
|
446
|
+
addedVarCount + 1
|
|
447
|
+
}}} to unsubscribe'`,
|
|
448
|
+
},
|
|
449
|
+
],
|
|
450
|
+
mediaType: 'text',
|
|
451
|
+
varMapped: {},
|
|
452
|
+
accountId,
|
|
453
|
+
accessToken,
|
|
454
|
+
accountName,
|
|
455
|
+
},
|
|
456
|
+
},
|
|
457
|
+
},
|
|
458
|
+
},
|
|
459
|
+
type: WHATSAPP,
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
const actionCallback = ({ errorMessage, resp }) => {
|
|
463
|
+
const error = errorMessage?.message || errorMessage;
|
|
464
|
+
if (!error) {
|
|
465
|
+
CapNotification.success({
|
|
466
|
+
message: formatMessage(messages.whatsappCreateNotification, {
|
|
467
|
+
name: templateName,
|
|
468
|
+
}),
|
|
469
|
+
});
|
|
470
|
+
actions.clearCreateResponse();
|
|
471
|
+
} else {
|
|
472
|
+
CapNotification.error({
|
|
473
|
+
message: error,
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
};
|
|
477
|
+
|
|
478
|
+
const createApprovalHandler = () => {
|
|
479
|
+
setSpin(true);
|
|
480
|
+
actions.createWhatsappTemplate(createPayload(), (resp, errorMessage) => {
|
|
481
|
+
actionCallback({ resp, errorMessage });
|
|
482
|
+
if (!errorMessage) {
|
|
483
|
+
onCreateComplete();
|
|
484
|
+
} else {
|
|
485
|
+
setSpin(false);
|
|
486
|
+
}
|
|
487
|
+
});
|
|
488
|
+
};
|
|
489
|
+
|
|
490
|
+
const onDoneCallback = () => {
|
|
491
|
+
if (isFullMode) {
|
|
492
|
+
return createApprovalHandler;
|
|
493
|
+
}
|
|
494
|
+
};
|
|
495
|
+
|
|
496
|
+
const isDisableDone = () => {
|
|
497
|
+
//if template name is not entered
|
|
498
|
+
if (templateName.trim() === '' || templateNameError) {
|
|
499
|
+
return true;
|
|
500
|
+
}
|
|
501
|
+
//if template category is not selected
|
|
502
|
+
if (templateCategory === 'Select') {
|
|
503
|
+
return true;
|
|
504
|
+
}
|
|
505
|
+
//if template message is not entered
|
|
506
|
+
if (templateMessage.trim() === '' || templateMessageError) {
|
|
507
|
+
return true;
|
|
508
|
+
}
|
|
509
|
+
return false;
|
|
510
|
+
};
|
|
511
|
+
|
|
512
|
+
const createModeContent = (
|
|
513
|
+
<>
|
|
514
|
+
{/* template name */}
|
|
515
|
+
<CapHeader
|
|
516
|
+
title={
|
|
517
|
+
<CapHeading type="h4">
|
|
518
|
+
{formatMessage(messages.templateNameLabel)}
|
|
519
|
+
<CapTooltipWithInfo
|
|
520
|
+
infoIconProps={{
|
|
521
|
+
style: { marginLeft: CAP_SPACE_04 },
|
|
522
|
+
}}
|
|
523
|
+
autoAdjustOverflow
|
|
524
|
+
title={<FormattedMessage {...messages.templateNameTooltip} />}
|
|
525
|
+
/>
|
|
526
|
+
</CapHeading>
|
|
527
|
+
}
|
|
528
|
+
description={
|
|
529
|
+
<CapLabel className="whatsapp-template-name-desc">
|
|
530
|
+
{formatMessage(messages.templateNameDesc)}
|
|
531
|
+
</CapLabel>
|
|
532
|
+
}
|
|
533
|
+
/>
|
|
534
|
+
<CapInput
|
|
535
|
+
id={`whatsapp_template_name_input`}
|
|
536
|
+
onChange={onTemplateNameChange}
|
|
537
|
+
errorMessage={templateNameError}
|
|
538
|
+
placeholder={formatMessage(messages.templateNamePlaceholder)}
|
|
539
|
+
defaultValue={templateName || ''}
|
|
540
|
+
value={templateName || ''}
|
|
541
|
+
size="default"
|
|
542
|
+
/>
|
|
543
|
+
{/* template category */}
|
|
544
|
+
{renderLabel('templateCategoryLabel')}
|
|
545
|
+
<CapSelect
|
|
546
|
+
id={'select-whatsapp-category'}
|
|
547
|
+
options={templateCategoryOptions || []}
|
|
548
|
+
onChange={onTemplateCategoryChange}
|
|
549
|
+
value={templateCategory}
|
|
550
|
+
/>
|
|
551
|
+
{/* template language */}
|
|
552
|
+
{renderLabel('messageLanguageLabel')}
|
|
553
|
+
<CapInput
|
|
554
|
+
id={`whatsapp_template_language_input`}
|
|
555
|
+
defaultValue={'English'}
|
|
556
|
+
size="default"
|
|
557
|
+
disabled={true}
|
|
558
|
+
/>
|
|
559
|
+
{/* template mdeia type */}
|
|
560
|
+
{renderLabel('mediaLabel')}
|
|
561
|
+
<CapRadioGroup options={mediaRadioOptions || []} defaultValue={'text'} />
|
|
562
|
+
{/* template message create flow */}
|
|
563
|
+
<CapHeading type="h4" className="whatsapp-render-heading">
|
|
564
|
+
{formatMessage(messages.templateMessageLabel)}
|
|
565
|
+
<CapTooltipWithInfo
|
|
566
|
+
placement="right"
|
|
567
|
+
infoIconProps={{
|
|
568
|
+
style: { marginLeft: CAP_SPACE_04 },
|
|
569
|
+
}}
|
|
570
|
+
autoAdjustOverflow
|
|
571
|
+
title={
|
|
572
|
+
<FormattedMessage
|
|
573
|
+
{...messages.templateMessageTooltip}
|
|
574
|
+
values={{
|
|
575
|
+
br: <br />,
|
|
576
|
+
var: '{{1}}',
|
|
577
|
+
}}
|
|
578
|
+
/>
|
|
579
|
+
}
|
|
580
|
+
/>
|
|
581
|
+
</CapHeading>
|
|
582
|
+
<CapRow className="whatsapp-create-template-message-input">
|
|
583
|
+
<TextArea
|
|
584
|
+
id={`whatsapp-create-template-message-input`}
|
|
585
|
+
autosize={{ minRows: 3, maxRows: 5 }}
|
|
586
|
+
placeholder={formatMessage(messages.templateMessagePlaceholder)}
|
|
587
|
+
onChange={onTemplateMessageChange}
|
|
588
|
+
errorMessage={
|
|
589
|
+
templateMessageError && (
|
|
590
|
+
<CapError className="whatsapp-template-message-error">
|
|
591
|
+
{templateMessageError}
|
|
592
|
+
</CapError>
|
|
593
|
+
)
|
|
594
|
+
}
|
|
595
|
+
value={templateMessage || ''}
|
|
596
|
+
/>
|
|
597
|
+
{renderUnsubscribeText()}
|
|
598
|
+
</CapRow>
|
|
599
|
+
{renderMessageLength()}
|
|
600
|
+
</>
|
|
601
|
+
);
|
|
602
|
+
//create methods end
|
|
603
|
+
|
|
604
|
+
//edit methods start
|
|
605
|
+
const getAlertType = () => {
|
|
606
|
+
if (templateStatus === WHATSAPP_STATUSES.approved) {
|
|
607
|
+
return 'success';
|
|
608
|
+
} else if (templateStatus === WHATSAPP_STATUSES.rejected) {
|
|
609
|
+
return 'error';
|
|
610
|
+
}
|
|
611
|
+
return 'warning';
|
|
612
|
+
};
|
|
613
|
+
|
|
614
|
+
const getAlertMessage = () => {
|
|
615
|
+
if (templateStatus === WHATSAPP_STATUSES.approved) {
|
|
616
|
+
return (
|
|
617
|
+
<CapLabel type="label2">
|
|
618
|
+
{formatMessage(messages.approvedStatusMsg)}
|
|
619
|
+
</CapLabel>
|
|
620
|
+
);
|
|
621
|
+
} else if (templateStatus === WHATSAPP_STATUSES.rejected) {
|
|
622
|
+
return (
|
|
623
|
+
<CapLabel type="label2">
|
|
624
|
+
{formatMessage(messages.rejectedStatusMsg)}
|
|
625
|
+
</CapLabel>
|
|
626
|
+
);
|
|
627
|
+
}
|
|
628
|
+
return (
|
|
629
|
+
<>
|
|
630
|
+
<CapLabel type="label2" style={{ fontWeight: 500 }}>
|
|
631
|
+
{formatMessage(messages.awaitingStatusMsg)}
|
|
632
|
+
</CapLabel>
|
|
633
|
+
<CapLabel
|
|
634
|
+
type="label2"
|
|
635
|
+
style={{ marginTop: CAP_SPACE_04, marginBottom: CAP_SPACE_04 }}
|
|
636
|
+
>
|
|
637
|
+
{formatMessage(messages.awaitingStatusDesc, {
|
|
638
|
+
date: moment(templateDate).format('D MMM YYYY'),
|
|
639
|
+
time: moment(templateDate).format('hh:mm A'),
|
|
640
|
+
})}
|
|
641
|
+
</CapLabel>
|
|
642
|
+
</>
|
|
643
|
+
);
|
|
644
|
+
};
|
|
645
|
+
|
|
646
|
+
// on change event of Text Area
|
|
647
|
+
const textAreaValueChange = ({ target: { value, id } }) => {
|
|
648
|
+
const numId = Number(id.slice(id.indexOf('_') + 1));
|
|
649
|
+
const arr = [...updatedSmsEditor];
|
|
650
|
+
|
|
651
|
+
//assign entered value to varMap
|
|
652
|
+
varMap[id] = value;
|
|
653
|
+
//based on entered value update updatedSmsEditor
|
|
654
|
+
if (value === '') {
|
|
655
|
+
arr[numId] = id.slice(0, id.indexOf('_'));
|
|
656
|
+
} else {
|
|
657
|
+
arr[numId] = value;
|
|
658
|
+
}
|
|
659
|
+
setUpdatedSmsEditor(arr);
|
|
660
|
+
};
|
|
661
|
+
|
|
662
|
+
const textAreaValue = (idValue) => {
|
|
663
|
+
if (idValue >= 0 && updatedSmsEditor) {
|
|
664
|
+
const value = updatedSmsEditor[idValue];
|
|
665
|
+
if (value && (value.match(validVarRegex) || []).length === 0) {
|
|
666
|
+
return value;
|
|
667
|
+
}
|
|
668
|
+
return '';
|
|
669
|
+
}
|
|
670
|
+
return '';
|
|
671
|
+
};
|
|
672
|
+
|
|
673
|
+
const renderedEditMessage = () => {
|
|
674
|
+
const renderArray = [];
|
|
675
|
+
if (tempMsgArray?.length !== 0) {
|
|
676
|
+
let varCount = 0;
|
|
677
|
+
tempMsgArray.forEach((elem, index) => {
|
|
678
|
+
if (elem.match(validVarRegex)?.length > 0) {
|
|
679
|
+
varCount += 1;
|
|
680
|
+
renderArray.push(
|
|
681
|
+
<TextArea
|
|
682
|
+
id={`${elem}_${index}`}
|
|
683
|
+
key={`${elem}_${index}`}
|
|
684
|
+
placeholder={formatMessage(messages.inputplaceHolderText, {
|
|
685
|
+
value: `{{${varCount}}}`,
|
|
686
|
+
})}
|
|
687
|
+
autosize={{ minRows: 1, maxRows: 3 }}
|
|
688
|
+
onChange={textAreaValueChange}
|
|
689
|
+
value={textAreaValue(index)}
|
|
690
|
+
onFocus={setTextAreaId}
|
|
691
|
+
disabled={templateStatus !== WHATSAPP_STATUSES.approved}
|
|
692
|
+
/>,
|
|
693
|
+
);
|
|
694
|
+
} else {
|
|
695
|
+
renderArray.push(
|
|
696
|
+
<CapHeading
|
|
697
|
+
key={`${elem}_${index}`}
|
|
698
|
+
type="h4"
|
|
699
|
+
className="whatsapp-edit-template-message-heading"
|
|
700
|
+
>
|
|
701
|
+
{elem}
|
|
702
|
+
</CapHeading>,
|
|
703
|
+
);
|
|
704
|
+
}
|
|
705
|
+
});
|
|
706
|
+
}
|
|
707
|
+
renderArray.push(renderUnsubscribeText());
|
|
708
|
+
return renderArray;
|
|
709
|
+
};
|
|
710
|
+
|
|
711
|
+
const editModeContent = (
|
|
712
|
+
<>
|
|
713
|
+
<CapAlert message={getAlertMessage()} type={getAlertType()} />
|
|
714
|
+
<CapRow className="whatsapp-render-heading">
|
|
715
|
+
<CapHeader
|
|
716
|
+
title={
|
|
717
|
+
<CapHeading type="h4">
|
|
718
|
+
{formatMessage(messages.templateMessageLabel)}
|
|
719
|
+
</CapHeading>
|
|
720
|
+
}
|
|
721
|
+
suffix={
|
|
722
|
+
templateStatus === WHATSAPP_STATUSES.approved && (
|
|
723
|
+
<TagList
|
|
724
|
+
label={formatMessage(messages.addLabels)}
|
|
725
|
+
onTagSelect={onTagSelect}
|
|
726
|
+
location={location}
|
|
727
|
+
tags={tags || []}
|
|
728
|
+
onContextChange={handleOnTagsContextChange}
|
|
729
|
+
injectedTags={injectedTags || {}}
|
|
730
|
+
/>
|
|
731
|
+
)
|
|
732
|
+
}
|
|
733
|
+
/>
|
|
734
|
+
</CapRow>
|
|
735
|
+
<CapTooltip
|
|
736
|
+
title={
|
|
737
|
+
templateStatus === WHATSAPP_STATUSES.approved
|
|
738
|
+
? ''
|
|
739
|
+
: templateStatus === WHATSAPP_STATUSES.rejected
|
|
740
|
+
? formatMessage(messages.disabledEditTooltip, {
|
|
741
|
+
status: templateStatus,
|
|
742
|
+
})
|
|
743
|
+
: formatMessage(messages.disabledEditTooltip, {
|
|
744
|
+
status: 'awaiting for approval',
|
|
745
|
+
})
|
|
746
|
+
}
|
|
747
|
+
>
|
|
748
|
+
<CapRow
|
|
749
|
+
className={`whatsapp-edit-template-message-input ${
|
|
750
|
+
templateStatus !== WHATSAPP_STATUSES.approved &&
|
|
751
|
+
'whatsapp-edit-disabled'
|
|
752
|
+
}`}
|
|
753
|
+
>
|
|
754
|
+
{renderedEditMessage()}
|
|
755
|
+
</CapRow>
|
|
756
|
+
</CapTooltip>
|
|
757
|
+
|
|
758
|
+
{renderMessageLength()}
|
|
759
|
+
</>
|
|
760
|
+
);
|
|
761
|
+
//edit methods end
|
|
762
|
+
|
|
763
|
+
const getPreviewSection = () => {
|
|
764
|
+
const templateMsg = `${
|
|
765
|
+
isEditFlow ? updatedSmsEditor.join('') : templateMessage
|
|
766
|
+
}\n${formatMessage(messages.templateMessageUnsubscribeText)}`;
|
|
767
|
+
return (
|
|
768
|
+
<TemplatePreview
|
|
769
|
+
channel={WHATSAPP}
|
|
770
|
+
content={{ templateMsg }}
|
|
771
|
+
whatsappAccountName={accountName}
|
|
772
|
+
/>
|
|
773
|
+
);
|
|
774
|
+
};
|
|
775
|
+
|
|
776
|
+
return (
|
|
777
|
+
<CapSpin spinning={spin}>
|
|
778
|
+
<CapRow>
|
|
779
|
+
<CapColumn span={14}>
|
|
780
|
+
{isEditFlow ? editModeContent : createModeContent}
|
|
781
|
+
<div className="whatsapp-scroll-div" />
|
|
782
|
+
</CapColumn>
|
|
783
|
+
<CapColumn span={6}>
|
|
784
|
+
<CapRow className={isEditFlow ? 'whatsapp-edit-alert-margin' : ''}>
|
|
785
|
+
<CapColumn span={24} offset={9}>
|
|
786
|
+
{getPreviewSection()}
|
|
787
|
+
</CapColumn>
|
|
788
|
+
</CapRow>
|
|
789
|
+
</CapColumn>
|
|
790
|
+
</CapRow>
|
|
791
|
+
<WhatsappFooter>
|
|
792
|
+
{!isEditFlow && (
|
|
793
|
+
<>
|
|
794
|
+
<CapButton
|
|
795
|
+
onClick={onDoneCallback()}
|
|
796
|
+
disabled={isDisableDone()}
|
|
797
|
+
className="whatsapp-create-btn"
|
|
798
|
+
>
|
|
799
|
+
<FormattedMessage {...messages.sendForApprovalButtonLabel} />
|
|
800
|
+
</CapButton>
|
|
801
|
+
<CapButton
|
|
802
|
+
onClick={handleClose}
|
|
803
|
+
className="whatsapp-cancel-btn"
|
|
804
|
+
type="secondary"
|
|
805
|
+
>
|
|
806
|
+
<FormattedMessage {...messages.cancelButtonLabel} />
|
|
807
|
+
</CapButton>
|
|
808
|
+
</>
|
|
809
|
+
)}
|
|
810
|
+
</WhatsappFooter>
|
|
811
|
+
</CapSpin>
|
|
812
|
+
);
|
|
813
|
+
};
|
|
814
|
+
|
|
815
|
+
const mapStateToProps = createStructuredSelector({
|
|
816
|
+
editData: makeSelectWhatsapp(),
|
|
817
|
+
accountData: makeSelectAccount(),
|
|
818
|
+
metaEntities: makeSelectMetaEntities(),
|
|
819
|
+
injectedTags: setInjectedTags(),
|
|
820
|
+
});
|
|
821
|
+
|
|
822
|
+
const mapDispatchToProps = (dispatch) => ({
|
|
823
|
+
actions: bindActionCreators(WhatsappActions, dispatch),
|
|
824
|
+
});
|
|
825
|
+
|
|
826
|
+
export default withCreatives({
|
|
827
|
+
WrappedComponent: injectIntl(Whatsapp),
|
|
828
|
+
mapStateToProps,
|
|
829
|
+
mapDispatchToProps,
|
|
830
|
+
userAuth: true,
|
|
831
|
+
});
|