@capillarytech/creatives-library 8.0.239 → 8.0.240
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/config/app.js +1 -0
- package/package.json +1 -1
- package/services/api.js +2 -0
- package/v2Containers/CreativesContainer/index.js +1 -1
- package/v2Containers/Rcs/index.js +58 -13
- package/v2Containers/Rcs/tests/index.test.js +81 -0
- package/v2Containers/Templates/index.js +1 -0
- package/v2Containers/Whatsapp/index.js +1 -0
package/config/app.js
CHANGED
|
@@ -21,6 +21,7 @@ const config = {
|
|
|
21
21
|
},
|
|
22
22
|
development: {
|
|
23
23
|
api_endpoint: 'https://crm-nightly-new.cc.capillarytech.com/arya/api/v1/creatives',
|
|
24
|
+
// api_endpoint: 'http://localhost:2022/arya/api/v1/creatives',
|
|
24
25
|
campaigns_api_endpoint: 'https://crm-nightly-new.cc.capillarytech.com/iris/v2/campaigns',
|
|
25
26
|
campaigns_api_org_endpoint: 'https://crm-nightly-new.cc.capillarytech.com/iris/v2/org/campaign',
|
|
26
27
|
auth_endpoint: 'https://crm-nightly-new.cc.capillarytech.com/arya/api/v1/auth',
|
package/package.json
CHANGED
package/services/api.js
CHANGED
|
@@ -264,6 +264,7 @@ export const getUserData = () => {
|
|
|
264
264
|
|
|
265
265
|
export const createTemplate = ({template}) => {
|
|
266
266
|
const url = `${API_ENDPOINT}/templates/SMS`;
|
|
267
|
+
console.log("creating template",template);
|
|
267
268
|
return request(url, getAPICallObject('POST', template));
|
|
268
269
|
};
|
|
269
270
|
|
|
@@ -346,6 +347,7 @@ export const getAllTemplates = async ({channel, queryParams = {}}) => {
|
|
|
346
347
|
|
|
347
348
|
export const deleteTemplate = ({channel, id}) => {
|
|
348
349
|
const url = `${API_ENDPOINT}/templates/${id}/${channel}`;
|
|
350
|
+
console.log("deleting template", url);
|
|
349
351
|
return request(url, getAPICallObject('DELETE'));
|
|
350
352
|
//return API.deleteResource(url);
|
|
351
353
|
};
|
|
@@ -675,7 +675,7 @@ export class Creatives extends React.Component {
|
|
|
675
675
|
} = templateData || {};
|
|
676
676
|
const cardContent = (rcsContent.cardContent && rcsContent.cardContent[0]) || {};
|
|
677
677
|
const Status = RCS_STATUSES.approved || '';
|
|
678
|
-
|
|
678
|
+
console.log("onedit data--------->",templateData);
|
|
679
679
|
creativesTemplateData = {
|
|
680
680
|
type: channel,
|
|
681
681
|
edit: true,
|
|
@@ -3,7 +3,7 @@ import React, { useState, useEffect, useCallback } from 'react';
|
|
|
3
3
|
import { bindActionCreators } from 'redux';
|
|
4
4
|
import { createStructuredSelector } from 'reselect';
|
|
5
5
|
import { injectIntl, FormattedMessage } from 'react-intl';
|
|
6
|
-
import { get, isEmpty, cloneDeep } from 'lodash';
|
|
6
|
+
import { get, isEmpty, cloneDeep, isNil } from 'lodash';
|
|
7
7
|
import styled from 'styled-components';
|
|
8
8
|
import CapSpin from '@capillarytech/cap-ui-library/CapSpin';
|
|
9
9
|
import CapRow from '@capillarytech/cap-ui-library/CapRow';
|
|
@@ -282,9 +282,22 @@ export const Rcs = (props) => {
|
|
|
282
282
|
if (type === MESSAGE_TEXT) setTemplateDescError(false);
|
|
283
283
|
return;
|
|
284
284
|
}
|
|
285
|
+
|
|
286
|
+
let contentForValidation = resolved;
|
|
287
|
+
const placeholderTokens = templateStr.match(rcsVarRegex) || [];
|
|
288
|
+
placeholderTokens.forEach((t) => {
|
|
289
|
+
const escaped = t.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
|
|
290
|
+
contentForValidation = contentForValidation.replace(new RegExp(escaped, 'g'), '');
|
|
291
|
+
});
|
|
292
|
+
if (!contentForValidation.trim()) {
|
|
293
|
+
if (type === TITLE_TEXT) setTemplateTitleError(false);
|
|
294
|
+
if (type === MESSAGE_TEXT) setTemplateDescError(false);
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
|
|
285
298
|
const validationResponse =
|
|
286
299
|
validateTags({
|
|
287
|
-
content:
|
|
300
|
+
content: contentForValidation,
|
|
288
301
|
tagsParam: tags,
|
|
289
302
|
injectedTagsParams: injectedTags,
|
|
290
303
|
location,
|
|
@@ -322,7 +335,8 @@ export const Rcs = (props) => {
|
|
|
322
335
|
if (rcsVarTestRegex.test(elem)) {
|
|
323
336
|
const key = getVarNameFromToken(elem);
|
|
324
337
|
const v = cardVarMapped?.[key];
|
|
325
|
-
|
|
338
|
+
if (isNil(v) || String(v)?.trim?.() === '') return elem;
|
|
339
|
+
return String(v);
|
|
326
340
|
}
|
|
327
341
|
return elem;
|
|
328
342
|
}).join('');
|
|
@@ -330,7 +344,7 @@ export const Rcs = (props) => {
|
|
|
330
344
|
|
|
331
345
|
|
|
332
346
|
useEffect(() => {
|
|
333
|
-
if (isFullMode) return;
|
|
347
|
+
if (isFullMode || isEditFlow) return;
|
|
334
348
|
const tokens = [
|
|
335
349
|
...(templateTitle ? (templateTitle.match(rcsVarRegex) || []) : []),
|
|
336
350
|
...(templateDesc ? (templateDesc.match(rcsVarRegex) || []) : []),
|
|
@@ -1729,8 +1743,7 @@ const splitTemplateVarString = (str) => {
|
|
|
1729
1743
|
const currentDimension =selectedDimension || Object.keys(RCS_VIDEO_THUMBNAIL_DIMENSIONS)[0];
|
|
1730
1744
|
return (
|
|
1731
1745
|
<>
|
|
1732
|
-
{renderLabel('cardOrientationLabel')}
|
|
1733
|
-
{/* Match image behavior: allow changing dimensions only in full-mode create flow */}
|
|
1746
|
+
{isFullMode && renderLabel('cardOrientationLabel')}
|
|
1734
1747
|
{!isEditFlow && isFullMode && (
|
|
1735
1748
|
<CapSelect
|
|
1736
1749
|
id="rcs-dimension-select"
|
|
@@ -1829,11 +1842,27 @@ const splitTemplateVarString = (str) => {
|
|
|
1829
1842
|
if (!str) return '';
|
|
1830
1843
|
if (!mapping || Object.keys(mapping).length === 0) return str;
|
|
1831
1844
|
let result = str;
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
const
|
|
1845
|
+
const replacements = [];
|
|
1846
|
+
Object.entries(mapping).forEach(([key, value]) => {
|
|
1847
|
+
const raw = (value ?? '').toString();
|
|
1848
|
+
if (!raw || raw?.trim?.() === '') return;
|
|
1849
|
+
const braced = /^\{\{[\s\S]*\}\}$/.test(raw) ? raw : `{{${raw}}}`;
|
|
1850
|
+
replacements.push({ key, needle: raw });
|
|
1851
|
+
if (braced !== raw) replacements.push({ key, needle: braced });
|
|
1852
|
+
});
|
|
1853
|
+
const seen = new Set();
|
|
1854
|
+
const uniq = replacements
|
|
1855
|
+
.filter(({ key, needle }) => {
|
|
1856
|
+
const id = `${key}::${needle}`;
|
|
1857
|
+
if (seen.has(id)) return false;
|
|
1858
|
+
seen.add(id);
|
|
1859
|
+
return true;
|
|
1860
|
+
})
|
|
1861
|
+
.sort((a, b) => (b.needle.length - a.needle.length));
|
|
1862
|
+
|
|
1863
|
+
uniq.forEach(({ key, needle }) => {
|
|
1864
|
+
if (!needle) return;
|
|
1865
|
+
const escaped = needle.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
|
|
1837
1866
|
const regex = new RegExp(escaped, 'g');
|
|
1838
1867
|
result = result.replace(regex, `{{${key}}}`);
|
|
1839
1868
|
});
|
|
@@ -1879,8 +1908,24 @@ const splitTemplateVarString = (str) => {
|
|
|
1879
1908
|
? RCS_IMAGE_DIMENSIONS[selectedDimension]?.heightType || MEDIUM
|
|
1880
1909
|
: RCS_VIDEO_THUMBNAIL_DIMENSIONS[selectedDimension]?.heightType || MEDIUM,
|
|
1881
1910
|
}}),
|
|
1882
|
-
|
|
1883
|
-
|
|
1911
|
+
...(!isFullMode && (() => {
|
|
1912
|
+
const tokens = [
|
|
1913
|
+
...(templateTitle ? (templateTitle.match(rcsVarRegex) || []) : []),
|
|
1914
|
+
...(templateDesc ? (templateDesc.match(rcsVarRegex) || []) : []),
|
|
1915
|
+
];
|
|
1916
|
+
const allowedKeys = tokens
|
|
1917
|
+
.map((t) => getVarNameFromToken(t))
|
|
1918
|
+
.filter(Boolean);
|
|
1919
|
+
const nextMap = {};
|
|
1920
|
+
allowedKeys.forEach((k) => {
|
|
1921
|
+
if (Object.prototype.hasOwnProperty.call(cardVarMapped || {}, k)) {
|
|
1922
|
+
nextMap[k] = cardVarMapped[k];
|
|
1923
|
+
} else {
|
|
1924
|
+
nextMap[k] = '';
|
|
1925
|
+
}
|
|
1926
|
+
});
|
|
1927
|
+
return { cardVarMapped: nextMap };
|
|
1928
|
+
})()),
|
|
1884
1929
|
...(suggestions.length > 0 && { suggestions }),
|
|
1885
1930
|
}
|
|
1886
1931
|
],
|
|
@@ -968,6 +968,87 @@ describe('RCS createPayload', () => {
|
|
|
968
968
|
expect(updatedTitleVarAreas.at(0).prop('value')).toBe('{{first_name}}');
|
|
969
969
|
expect(updatedTitleVarAreas.at(1).prop('value')).toBe('{{first_name}}');
|
|
970
970
|
});
|
|
971
|
+
|
|
972
|
+
it('should keep two tags + freetext inside the variable textarea in non-full mode edit (not merged into static text)', () => {
|
|
973
|
+
const templateData = {
|
|
974
|
+
name: 'TwoTagsAndFreeText',
|
|
975
|
+
versions: {
|
|
976
|
+
base: {
|
|
977
|
+
content: {
|
|
978
|
+
RCS: {
|
|
979
|
+
rcsContent: {
|
|
980
|
+
cardType: 'STANDALONE',
|
|
981
|
+
cardSettings: { cardOrientation: 'VERTICAL', cardWidth: 'SMALL' },
|
|
982
|
+
cardContent: [
|
|
983
|
+
{
|
|
984
|
+
// NOTE: In campaigns/edit flows, title/description can be stored "resolved" (values applied).
|
|
985
|
+
// We expect RCS to "unmap" this back to placeholders and show values in variable textareas.
|
|
986
|
+
title: 'Update for {{user_id_b64}} regarding {{first_name}}{{adv}}freeText',
|
|
987
|
+
description: 'Hi {{user_id_b64}}, your {{first_name}}{{adv}}freeText is ready.',
|
|
988
|
+
mediaType: 'NONE',
|
|
989
|
+
cardVarMapped: {
|
|
990
|
+
user_name: '{{user_id_b64}}',
|
|
991
|
+
service_type: '{{first_name}}{{adv}}freeText',
|
|
992
|
+
},
|
|
993
|
+
suggestions: [],
|
|
994
|
+
},
|
|
995
|
+
],
|
|
996
|
+
contentType: 'RICHCARD',
|
|
997
|
+
},
|
|
998
|
+
},
|
|
999
|
+
},
|
|
1000
|
+
},
|
|
1001
|
+
},
|
|
1002
|
+
type: 'RCS',
|
|
1003
|
+
};
|
|
1004
|
+
|
|
1005
|
+
const wrapper = mountWithIntl(
|
|
1006
|
+
<Provider store={store}>
|
|
1007
|
+
<Rcs
|
|
1008
|
+
actions={{
|
|
1009
|
+
clearCreateResponse: jest.fn(),
|
|
1010
|
+
getTemplateDetails: jest.fn(),
|
|
1011
|
+
uploadRcsAsset: jest.fn(),
|
|
1012
|
+
clearRcsMediaAsset: jest.fn(),
|
|
1013
|
+
editTemplate: jest.fn(),
|
|
1014
|
+
clearEditResponse: jest.fn(),
|
|
1015
|
+
}}
|
|
1016
|
+
globalActions={{ fetchSchemaForEntity }}
|
|
1017
|
+
onCreateComplete={onCreateComplete}
|
|
1018
|
+
handleClose={handleClose}
|
|
1019
|
+
intl={{ formatMessage }}
|
|
1020
|
+
location={{ pathname: '/rcs/edit', query: { type: false, module: 'default' }, search: '' }}
|
|
1021
|
+
params={params}
|
|
1022
|
+
templateData={templateData}
|
|
1023
|
+
rcsData={{}}
|
|
1024
|
+
isFullMode={false}
|
|
1025
|
+
isEditFlow={false}
|
|
1026
|
+
loadingTags={false}
|
|
1027
|
+
metaEntities={[]}
|
|
1028
|
+
isDltEnabled={false}
|
|
1029
|
+
smsRegister={'DLT'}
|
|
1030
|
+
getFormData={jest.fn()}
|
|
1031
|
+
/>
|
|
1032
|
+
</Provider>,
|
|
1033
|
+
);
|
|
1034
|
+
|
|
1035
|
+
wrapper.update();
|
|
1036
|
+
|
|
1037
|
+
// The placeholder {{service_type}} should exist as a variable textarea id, and its value should be the mixed string.
|
|
1038
|
+
const serviceTypeAreas = wrapper.find('TextArea').filterWhere((n) => {
|
|
1039
|
+
const id = n.prop('id') || '';
|
|
1040
|
+
return id.includes('{{service_type}}_');
|
|
1041
|
+
});
|
|
1042
|
+
expect(serviceTypeAreas.length).toBeGreaterThanOrEqual(1);
|
|
1043
|
+
expect(serviceTypeAreas.at(0).prop('value')).toBe('{{first_name}}{{adv}}freeText');
|
|
1044
|
+
|
|
1045
|
+
// Ensure freetext does NOT leak into static text blocks.
|
|
1046
|
+
const staticAreas = wrapper.find('TextArea').filterWhere((n) => !!n.prop('disabled'));
|
|
1047
|
+
const staticValues = staticAreas.map((n) => String(n.prop('value') || ''));
|
|
1048
|
+
staticValues.forEach((v) => {
|
|
1049
|
+
expect(v.includes('freeText')).toBe(false);
|
|
1050
|
+
});
|
|
1051
|
+
});
|
|
971
1052
|
});
|
|
972
1053
|
|
|
973
1054
|
describe('Character Counting Functions', () => {
|
|
@@ -1146,6 +1146,7 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
|
|
|
1146
1146
|
}
|
|
1147
1147
|
|
|
1148
1148
|
filterRcsTemplates = (templates) => {
|
|
1149
|
+
console.log('templates', templates);
|
|
1149
1150
|
let { selectedRcsStatus } = this.state;
|
|
1150
1151
|
selectedRcsStatus = !this.props.isFullMode ? RCS_STATUSES.approved : '';
|
|
1151
1152
|
if (selectedRcsStatus) {
|
|
@@ -290,6 +290,7 @@ export const Whatsapp = (props) => {
|
|
|
290
290
|
//gets account details
|
|
291
291
|
useEffect(() => {
|
|
292
292
|
const accountObj = accountData.selectedWhatsappAccount || {};
|
|
293
|
+
console.log('accountObj', accountObj);
|
|
293
294
|
if (!isEmpty(accountObj)) {
|
|
294
295
|
const {
|
|
295
296
|
sourceAccountIdentifier = '',
|