@capillarytech/creatives-library 8.0.301 → 8.0.303
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/constants/unified.js +1 -0
- package/package.json +1 -1
- package/utils/common.js +7 -1
- package/v2Components/CapDeviceContent/index.js +10 -7
- package/v2Components/FormBuilder/index.js +1 -1
- package/v2Components/HtmlEditor/HTMLEditor.js +1 -0
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +1 -0
- package/v2Components/HtmlEditor/hooks/__tests__/useValidation.test.js +132 -3
- package/v2Components/HtmlEditor/hooks/useValidation.js +12 -9
- package/v2Components/HtmlEditor/utils/htmlValidator.js +4 -2
- package/v2Containers/BeePopupEditor/index.js +9 -2
- package/v2Containers/CreativesContainer/SlideBoxContent.js +35 -3
- package/v2Containers/CreativesContainer/tests/SlideBoxContent.test.js +69 -1
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +121 -4
- package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +2 -2
- package/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +110 -18
- package/v2Containers/InApp/__tests__/InAppHTMLEditor.test.js +110 -155
- package/v2Containers/InApp/index.js +183 -14
- package/v2Containers/InApp/tests/mockData.js +1 -1
|
@@ -14,6 +14,8 @@ import CapRow from "@capillarytech/cap-ui-library/CapRow";
|
|
|
14
14
|
import CapColumn from "@capillarytech/cap-ui-library/CapColumn";
|
|
15
15
|
import CapButton from "@capillarytech/cap-ui-library/CapButton";
|
|
16
16
|
import CapNotification from "@capillarytech/cap-ui-library/CapNotification";
|
|
17
|
+
import CapTab from "@capillarytech/cap-ui-library/CapTab";
|
|
18
|
+
import CapInput from "@capillarytech/cap-ui-library/CapInput";
|
|
17
19
|
import { makeSelectInApp, makeSelectAccount, makeSelectGetTemplateDetailsInProgress } from "./selectors";
|
|
18
20
|
import * as globalActions from '../Cap/actions';
|
|
19
21
|
import {
|
|
@@ -52,18 +54,20 @@ import {
|
|
|
52
54
|
IOS_CAPITAL,
|
|
53
55
|
} from "./constants";
|
|
54
56
|
import { INAPP, SMS } from "../CreativesContainer/constants";
|
|
57
|
+
import { AI_CONTENT_BOT_DISABLED } from "../../constants/unified";
|
|
55
58
|
import {
|
|
56
59
|
ALL, TAG, EMBEDDED, DEFAULT, FULL, LIBRARY,
|
|
57
60
|
} from "../Whatsapp/constants";
|
|
58
61
|
import { getCdnUrl } from "../../utils/cdnTransformation";
|
|
59
62
|
import { getCtaObject, hasAnyErrors, getSingleTab } from "./utils";
|
|
60
63
|
import { validateInAppContent } from "../../utils/commonUtils";
|
|
61
|
-
import { hasLiquidSupportFeature } from "../../utils/common";
|
|
64
|
+
import { hasLiquidSupportFeature, hasNewEditorFlowInAppEnabled } from "../../utils/common";
|
|
62
65
|
import formBuilderMessages from "../../v2Components/FormBuilder/messages";
|
|
63
66
|
import HTMLEditor from "../../v2Components/HtmlEditor";
|
|
64
67
|
import { HTML_EDITOR_VARIANTS } from "../../v2Components/HtmlEditor/constants";
|
|
65
68
|
import { INAPP_EDITOR_TYPES } from "../InAppWrapper/constants";
|
|
66
69
|
import InappAdvanced from "../InappAdvance/index";
|
|
70
|
+
import CapDeviceContent from "../../v2Components/CapDeviceContent";
|
|
67
71
|
import { ErrorInfoNote } from "../../v2Components/ErrorInfoNote";
|
|
68
72
|
|
|
69
73
|
let editContent = {};
|
|
@@ -74,6 +78,7 @@ export const InApp = (props) => {
|
|
|
74
78
|
actions,
|
|
75
79
|
globalActions,
|
|
76
80
|
isFullMode,
|
|
81
|
+
isLoyaltyModule,
|
|
77
82
|
onCreateComplete,
|
|
78
83
|
params,
|
|
79
84
|
templateData = {},
|
|
@@ -878,7 +883,7 @@ export const InApp = (props) => {
|
|
|
878
883
|
// Use 'html editor template' as title for HTML editor to differentiate from BEE editor
|
|
879
884
|
title: isHTMLTemplate ? 'html editor template' : titleAndroid,
|
|
880
885
|
message: androidMessage,
|
|
881
|
-
bodyType:
|
|
886
|
+
bodyType: bodyTypeForBackend,
|
|
882
887
|
expandableDetails: {
|
|
883
888
|
style: androidExpandableStyle,
|
|
884
889
|
message: androidMessage,
|
|
@@ -1240,11 +1245,13 @@ export const InApp = (props) => {
|
|
|
1240
1245
|
&& !isBEEeditor
|
|
1241
1246
|
&& !isBeeFreeTemplate;
|
|
1242
1247
|
|
|
1248
|
+
const isNewEditorFlowEnabled = !isLoyaltyModule && hasNewEditorFlowInAppEnabled();
|
|
1249
|
+
|
|
1243
1250
|
// Use state if available, otherwise fall back to direct data check
|
|
1244
|
-
const shouldUseHTMLEditor = isHTMLTemplate || isHTMLTemplateFromData;
|
|
1251
|
+
const shouldUseHTMLEditor = isNewEditorFlowEnabled && (isHTMLTemplate || isHTMLTemplateFromData);
|
|
1245
1252
|
|
|
1246
1253
|
// Only route to Bee editor if it's explicitly a Bee editor AND not an HTML template
|
|
1247
|
-
const shouldUseBeeEditor = (isBEEeditor || isBeeFreeTemplate) && !shouldUseHTMLEditor;
|
|
1254
|
+
const shouldUseBeeEditor = isNewEditorFlowEnabled && (isBEEeditor || isBeeFreeTemplate) && !shouldUseHTMLEditor;
|
|
1248
1255
|
|
|
1249
1256
|
// Early returns to avoid nested ternary
|
|
1250
1257
|
if (isEditInApp && getTemplateDetailsInProgress) {
|
|
@@ -1280,10 +1287,157 @@ export const InApp = (props) => {
|
|
|
1280
1287
|
);
|
|
1281
1288
|
}
|
|
1282
1289
|
|
|
1290
|
+
// ── Old-flow helpers (used by CapDeviceContent when flag is disabled) ──────
|
|
1291
|
+
const isAiContentBotDisabled = currentOrgDetails?.accessibleFeatures?.includes(AI_CONTENT_BOT_DISABLED);
|
|
1292
|
+
|
|
1293
|
+
const templateDescErrorHandler = (value) => {
|
|
1294
|
+
const { unsupportedTags, isBraceError } = validateTags({
|
|
1295
|
+
content: value,
|
|
1296
|
+
tagsParam: tags,
|
|
1297
|
+
injectedTagsParams: injectedTags,
|
|
1298
|
+
location,
|
|
1299
|
+
tagModule: getDefaultTags,
|
|
1300
|
+
isFullMode,
|
|
1301
|
+
}) || {};
|
|
1302
|
+
if (unsupportedTags?.length > 0) {
|
|
1303
|
+
return formatMessage(globalMessages.unsupportedTagsValidationError, { unsupportedTags });
|
|
1304
|
+
}
|
|
1305
|
+
if (isBraceError) {
|
|
1306
|
+
return formatMessage(globalMessages.braceValidationError);
|
|
1307
|
+
}
|
|
1308
|
+
return '';
|
|
1309
|
+
};
|
|
1310
|
+
|
|
1311
|
+
const onCopyTitleAndContent = () => {
|
|
1312
|
+
if (panes === ANDROID) {
|
|
1313
|
+
setTitleAndroid(titleIos);
|
|
1314
|
+
setTemplateMessageAndroid(templateMessageIos);
|
|
1315
|
+
setInAppImageSrcAndroid(inAppImageSrcIos);
|
|
1316
|
+
} else {
|
|
1317
|
+
setTitleIos(titleAndroid);
|
|
1318
|
+
setTemplateMessageIos(templateMessageAndroid);
|
|
1319
|
+
setInAppImageSrcIos(inAppImageSrcAndroid);
|
|
1320
|
+
}
|
|
1321
|
+
};
|
|
1322
|
+
|
|
1323
|
+
const onTagSelect = (value, index) => {
|
|
1324
|
+
const tag = `{{${value}}}`;
|
|
1325
|
+
if (panes === ANDROID) {
|
|
1326
|
+
if (index === 0) setTitleAndroid((prev) => prev + tag);
|
|
1327
|
+
else setTemplateMessageAndroid((prev) => prev + tag);
|
|
1328
|
+
} else if (index === 0) {
|
|
1329
|
+
setTitleIos((prev) => prev + tag);
|
|
1330
|
+
} else {
|
|
1331
|
+
setTemplateMessageIos((prev) => prev + tag);
|
|
1332
|
+
}
|
|
1333
|
+
};
|
|
1334
|
+
|
|
1335
|
+
// Device support flags (same derivation as InappAdvance)
|
|
1336
|
+
const isAndroidSupported = get(accountData, 'selectedWeChatAccount.configs.android') === DEVICE_SUPPORTED || get(editContent, 'ANDROID.deviceType') === ANDROID;
|
|
1337
|
+
const isIosSupported = get(accountData, 'selectedWeChatAccount.configs.ios') === DEVICE_SUPPORTED || get(editContent, 'IOS.deviceType') === IOS_CAPITAL;
|
|
1338
|
+
|
|
1339
|
+
// CapDeviceContent tab panes (old flow)
|
|
1340
|
+
const DEVICE_PANES = [
|
|
1341
|
+
{
|
|
1342
|
+
content: (
|
|
1343
|
+
<CapDeviceContent
|
|
1344
|
+
panes={ANDROID}
|
|
1345
|
+
actions={actions}
|
|
1346
|
+
editData={editData}
|
|
1347
|
+
isFullMode={isFullMode}
|
|
1348
|
+
inAppImageSrc={inAppImageSrcAndroid}
|
|
1349
|
+
setInAppImageSrc={setInAppImageSrcAndroid}
|
|
1350
|
+
isEditFlow={isEditFlow}
|
|
1351
|
+
ctaData={ctaDataAndroid}
|
|
1352
|
+
setCtaData={setCtaDataAndroid}
|
|
1353
|
+
buttonType={buttonTypeAndroid}
|
|
1354
|
+
setButtonType={setButtonTypeAndroid}
|
|
1355
|
+
templateMediaType={templateMediaType}
|
|
1356
|
+
setTemplateMediaType={setTemplateMediaType}
|
|
1357
|
+
title={titleAndroid}
|
|
1358
|
+
setTitle={setTitleAndroid}
|
|
1359
|
+
templateMessageError={templateMessageErrorAndroid}
|
|
1360
|
+
templateMessage={templateMessageAndroid}
|
|
1361
|
+
setTemplateMessage={setTemplateMessageAndroid}
|
|
1362
|
+
setTemplateMessageError={setTemplateMessageErrorAndroid}
|
|
1363
|
+
addActionLink={addActionLinkAndroid}
|
|
1364
|
+
setAddActionLink={setAddActionLinkAndroid}
|
|
1365
|
+
deepLink={deepLink}
|
|
1366
|
+
deepLinkValue={deepLinkValueAndroid}
|
|
1367
|
+
setDeepLinkValue={setDeepLinkValueAndroid}
|
|
1368
|
+
onCopyTitleAndContent={onCopyTitleAndContent}
|
|
1369
|
+
isOtherDeviceSupported={isIosSupported}
|
|
1370
|
+
tags={tags}
|
|
1371
|
+
onTagSelect={onTagSelect}
|
|
1372
|
+
handleOnTagsContextChange={handleOnTagsContextChange}
|
|
1373
|
+
templateDescErrorHandler={templateDescErrorHandler}
|
|
1374
|
+
templateTitleError={templateTitleErrorAndroid}
|
|
1375
|
+
setTemplateTitleError={setTemplateTitleErrorAndroid}
|
|
1376
|
+
isAiContentBotDisabled={isAiContentBotDisabled}
|
|
1377
|
+
injectedTags={injectedTags}
|
|
1378
|
+
selectedOfferDetails={selectedOfferDetails}
|
|
1379
|
+
location={location}
|
|
1380
|
+
/>
|
|
1381
|
+
),
|
|
1382
|
+
tab: <FormattedMessage {...messages.Android} />,
|
|
1383
|
+
key: ANDROID,
|
|
1384
|
+
isSupported: isAndroidSupported,
|
|
1385
|
+
},
|
|
1386
|
+
{
|
|
1387
|
+
content: (
|
|
1388
|
+
<CapDeviceContent
|
|
1389
|
+
panes={IOS}
|
|
1390
|
+
actions={actions}
|
|
1391
|
+
editData={editData}
|
|
1392
|
+
isFullMode={isFullMode}
|
|
1393
|
+
inAppImageSrc={inAppImageSrcIos}
|
|
1394
|
+
setInAppImageSrc={setInAppImageSrcIos}
|
|
1395
|
+
isEditFlow={isEditFlow}
|
|
1396
|
+
ctaData={ctaDataIos}
|
|
1397
|
+
setCtaData={setCtaDataIos}
|
|
1398
|
+
buttonType={buttonTypeIos}
|
|
1399
|
+
setButtonType={setButtonTypeIos}
|
|
1400
|
+
templateMediaType={templateMediaType}
|
|
1401
|
+
setTemplateMediaType={setTemplateMediaType}
|
|
1402
|
+
title={titleIos}
|
|
1403
|
+
setTitle={setTitleIos}
|
|
1404
|
+
templateMessageError={templateMessageErrorIos}
|
|
1405
|
+
templateMessage={templateMessageIos}
|
|
1406
|
+
setTemplateMessage={setTemplateMessageIos}
|
|
1407
|
+
setTemplateMessageError={setTemplateMessageErrorIos}
|
|
1408
|
+
addActionLink={addActionLinkIos}
|
|
1409
|
+
setAddActionLink={setAddActionLinkIos}
|
|
1410
|
+
deepLink={deepLink}
|
|
1411
|
+
deepLinkValue={deepLinkValueIos}
|
|
1412
|
+
setDeepLinkValue={setDeepLinkValueIos}
|
|
1413
|
+
onCopyTitleAndContent={onCopyTitleAndContent}
|
|
1414
|
+
isOtherDeviceSupported={isAndroidSupported}
|
|
1415
|
+
tags={tags}
|
|
1416
|
+
onTagSelect={onTagSelect}
|
|
1417
|
+
handleOnTagsContextChange={handleOnTagsContextChange}
|
|
1418
|
+
templateDescErrorHandler={templateDescErrorHandler}
|
|
1419
|
+
templateTitleError={templateTitleErrorIos}
|
|
1420
|
+
setTemplateTitleError={setTemplateTitleErrorIos}
|
|
1421
|
+
isAiContentBotDisabled={isAiContentBotDisabled}
|
|
1422
|
+
injectedTags={injectedTags}
|
|
1423
|
+
selectedOfferDetails={selectedOfferDetails}
|
|
1424
|
+
location={location}
|
|
1425
|
+
/>
|
|
1426
|
+
),
|
|
1427
|
+
tab: <FormattedMessage {...messages.Ios} />,
|
|
1428
|
+
key: IOS,
|
|
1429
|
+
isSupported: isIosSupported,
|
|
1430
|
+
},
|
|
1431
|
+
];
|
|
1432
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
1433
|
+
|
|
1434
|
+
// Calculate column span: HTML editor = 18, everything else = 24
|
|
1435
|
+
const editorColumnSpan = shouldUseHTMLEditor ? 18 : 24;
|
|
1436
|
+
|
|
1283
1437
|
return (
|
|
1284
1438
|
<CapSpin spinning={spin || fetchingLiquidValidation} tip={fetchingLiquidValidation ? <FormattedMessage {...formBuilderMessages.liquidSpinText} /> : ""}>
|
|
1285
1439
|
<CapRow className="cap-inapp-creatives">
|
|
1286
|
-
<CapColumn span={
|
|
1440
|
+
<CapColumn span={editorColumnSpan}>
|
|
1287
1441
|
{/* Creative layout type */}
|
|
1288
1442
|
{shouldUseHTMLEditor && (
|
|
1289
1443
|
<>
|
|
@@ -1304,7 +1458,7 @@ export const InApp = (props) => {
|
|
|
1304
1458
|
/>
|
|
1305
1459
|
</>
|
|
1306
1460
|
)}
|
|
1307
|
-
{shouldUseHTMLEditor
|
|
1461
|
+
{shouldUseHTMLEditor && (
|
|
1308
1462
|
<HTMLEditor
|
|
1309
1463
|
key={`inapp-html-editor-v${htmlEditorContentVersion}`}
|
|
1310
1464
|
variant={HTML_EDITOR_VARIANTS.INAPP}
|
|
@@ -1320,19 +1474,16 @@ export const InApp = (props) => {
|
|
|
1320
1474
|
location={location}
|
|
1321
1475
|
selectedOfferDetails={selectedOfferDetails}
|
|
1322
1476
|
onTagSelect={() => {
|
|
1323
|
-
// Tag insertion
|
|
1324
|
-
// Content updates will be propagated via onContentChange callback
|
|
1477
|
+
// Tag insertion handled by HTMLEditor's CodeEditorPane at cursor position
|
|
1325
1478
|
}}
|
|
1326
|
-
// Don't pass globalActions to prevent duplicate API calls
|
|
1327
|
-
// HTMLEditor will use onContextChange instead
|
|
1328
1479
|
onContextChange={handleOnTagsContextChange}
|
|
1329
|
-
// Pass validation errors to HTMLEditor for display
|
|
1330
1480
|
errors={errorMessage}
|
|
1331
1481
|
isFullMode={isFullMode}
|
|
1332
1482
|
data-test="inapp-html-editor"
|
|
1333
1483
|
style={{ width: '138%' }}
|
|
1334
1484
|
/>
|
|
1335
|
-
)
|
|
1485
|
+
)}
|
|
1486
|
+
{!shouldUseHTMLEditor && isNewEditorFlowEnabled && (
|
|
1336
1487
|
<InappAdvanced
|
|
1337
1488
|
getFormData={getFormData}
|
|
1338
1489
|
setIsLoadingContent={setIsLoadingContent}
|
|
@@ -1357,11 +1508,29 @@ export const InApp = (props) => {
|
|
|
1357
1508
|
onCreateComplete={onCreateComplete}
|
|
1358
1509
|
/>
|
|
1359
1510
|
)}
|
|
1511
|
+
{!shouldUseHTMLEditor && !isNewEditorFlowEnabled && (
|
|
1512
|
+
<>
|
|
1513
|
+
<CapInput
|
|
1514
|
+
label={<FormattedMessage {...messages.creativeName} />}
|
|
1515
|
+
onChange={({ target: { value } }) => setTempName(value)}
|
|
1516
|
+
value={tempName}
|
|
1517
|
+
labelPosition="top"
|
|
1518
|
+
size="default"
|
|
1519
|
+
/>
|
|
1520
|
+
<CapTab
|
|
1521
|
+
panes={DEVICE_PANES.filter((devicePane) => devicePane?.isSupported === true)}
|
|
1522
|
+
onChange={(value) => setPanes(value)}
|
|
1523
|
+
activeKey={panes}
|
|
1524
|
+
defaultActiveKey={panes}
|
|
1525
|
+
className="inapp-template-device-tab"
|
|
1526
|
+
/>
|
|
1527
|
+
</>
|
|
1528
|
+
)}
|
|
1360
1529
|
</CapColumn>
|
|
1361
1530
|
</CapRow>
|
|
1362
|
-
{/* Footer with Done/Update button -
|
|
1531
|
+
{/* Footer with Done/Update button - show for HTML editor and old CapDeviceContent flow */}
|
|
1363
1532
|
{
|
|
1364
|
-
shouldUseHTMLEditor && (
|
|
1533
|
+
(shouldUseHTMLEditor || !isNewEditorFlowEnabled) && (
|
|
1365
1534
|
<>
|
|
1366
1535
|
{hasAnyErrors(errorMessage) && (
|
|
1367
1536
|
<ErrorInfoNote
|