Skip to content

Commit

Permalink
Add UI for auto-click tracking feature
Browse files Browse the repository at this point in the history
  • Loading branch information
jonsnyder committed May 10, 2024
1 parent 74fa62f commit 64fe904
Show file tree
Hide file tree
Showing 5 changed files with 180 additions and 29 deletions.
51 changes: 41 additions & 10 deletions scripts/helpers/createExtensionManifest.mjs
Expand Up @@ -310,6 +310,19 @@ const createExtensionManifest = ({ version }) => {
edgeConfigOverrides: createEdgeConfigOverridesSchema(false),
personalizationStorageEnabled: {
type: "boolean"
},
autoTrackPropositionInteractions: {
type: "object",
properties: {
AJO: {
type: "string",
enum: ["always", "decoratedElementsOnly", "never"]
},
TGT: {
type: "string",
enum: ["always", "decoratedElementsOnly", "never"]
}
},
}
},
required: ["edgeConfigId", "name"],
Expand Down Expand Up @@ -702,18 +715,36 @@ const createExtensionManifest = ({ version }) => {
{
type: "object",
additionalProperties: {
type: "object",
properties: {
selector: {
type: "string",
minLength: 1
anyOf: [
{
type: "object",
properties: {
selector: {
type: "string",
minLength: 1
},
actionType: {
type: "string",
enum: ["setHtml", "replaceHtml", "appendHtml", "track"]
}
},
required: ["selector", "actionType"]
},
actionType: {
type: "string",
enum: ["setHtml", "replaceHtml", "appendHtml"]
{
type: "object",
properties: {
element: {
type: "string",
pattern: "^%[^%]+%$"
},
actionType: {
type: "string",
enum: ["setHtml", "replaceHtml", "appendHtml", "track"]
}
},
required: ["element", "actionType"]
}
},
required: ["selector", "actionType"]
]
}
}
]
Expand Down
91 changes: 84 additions & 7 deletions src/view/actions/applyPropositions.jsx
Expand Up @@ -17,8 +17,46 @@ import textField from "../forms/textField";
import objectArray from "../forms/objectArray";
import dataElement from "../forms/dataElement";
import comboBox from "../forms/comboBox";
import radioGroup from "../forms/radioGroup";
import conditional from "../forms/conditional";
import { DATA_ELEMENT_REQUIRED } from "../constants/validationErrorMessages";
import singleDataElementRegex from "../constants/singleDataElementRegex";

const applyPropositionsForm = form({}, [
const wrapGetInitialValues = getInitialValues => args => {
const initialValues = getInitialValues(args);
if (initialValues.metadata && initialValues.metadata.length > 0) {
initialValues.metadata = initialValues.metadata.map(
({ scope, selector, element, actionType }) => {
return {
scope,
selector,
element,
actionType,
elementType: element ? "element" : "selector"
};
}
);
}
return initialValues;
};

const wrapGetSettings = getSettings => args => {
const settings = getSettings(args);
if (settings.metadata && settings.metadata.length > 0) {
settings.metadata = Object.keys(settings.metadata || {}).reduce(
(memo, scope) => {
// eslint-disable-next-line unused-imports/no-unused-vars
const { elementType, ...rest } = settings.metadata[scope];
memo[scope] = rest;
return memo;
},
{}
);
}
return settings;
};

const applyPropositionsForm = form({ wrapGetInitialValues, wrapGetSettings }, [
instancePicker({ name: "instanceName" }),
dataElement({
name: "propositions",
Expand Down Expand Up @@ -50,20 +88,59 @@ const applyPropositionsForm = form({}, [
description: "Enter your scope",
validationSchemaBase: string().required("Please provide a scope.")
}),
textField({
name: "selector",
label: "Selector",
description: "Enter your selector",
validationSchemaBase: string().required("Please provide a selector.")
radioGroup({
name: "elementType",
label: "Target element",
items: [
{ value: "selector", label: "Selector" },
{ value: "element", label: "Element" }
],
defaultValue: "selector",
orientation: "horizontal",
dataElementSupported: false
}),
conditional(
{
args: "elementType",
condition: elementType => elementType === "selector"
},
[
textField({
name: "selector",
ariaLabel: "Selector",
description: "Enter a css-selector for the target element.",
validationSchemaBase: string().required(
"Please provide a selector."
)
})
]
),
conditional(
{
args: "elementType",
condition: elementType => elementType === "element"
},
[
textField({
name: "element",
ariaLabel: "Element",
description:
"Provide a data element that resolves to a DOM element.",
validationSchemaBase: string()
.required("Please provide an element.")
.matches(singleDataElementRegex, DATA_ELEMENT_REQUIRED)
})
]
),
comboBox({
name: "actionType",
label: "Action Type",
description: "Select your action type",
items: [
{ value: "setHtml", label: "Set HTML" },
{ value: "replaceHtml", label: "Replace HTML" },
{ value: "appendHtml", label: "Append HTML" }
{ value: "appendHtml", label: "Append HTML" },
{ value: "track", label: "Track" }
],
validationSchemaBase: string().required(
"Please provide an action type."
Expand Down
44 changes: 41 additions & 3 deletions src/view/configuration/personalizationSection.jsx
Expand Up @@ -13,6 +13,7 @@ governing permissions and limitations under the License.
import copyToClipboard from "clipboard-copy";
import React from "react";
import PropTypes from "prop-types";
import { Radio } from "@adobe/react-spectrum";
import SectionHeader from "../components/sectionHeader";
import CodeField from "../components/codeField";
import CodePreview from "../components/codePreview";
Expand All @@ -22,24 +23,34 @@ import copyPropertiesWithDefaultFallback from "./utils/copyPropertiesWithDefault
import FormElementContainer from "../components/formElementContainer";
import FormikCheckbox from "../components/formikReactSpectrum3/formikCheckbox";
import BetaBadge from "../components/betaBadge";
import FormikRadioGroup from "../components/formikReactSpectrum3/formikRadioGroup";

export const bridge = {
getInstanceDefaults: () => ({
prehidingStyle: "",
targetMigrationEnabled: false,
personalizationStorageEnabled: false
personalizationStorageEnabled: false,
autoTrackPropositionInteractions: "always"
}),
getInitialInstanceValues: ({ instanceSettings }) => {
const instanceValues = {};

if (instanceSettings.autoTrackPropositionInteractions?.AJO) {
instanceSettings.autoTrackPropositionInteractions =
instanceSettings.autoTrackPropositionInteractions.AJO;
} else {
delete instanceSettings.autoTrackPropositionInteractions;
}

copyPropertiesWithDefaultFallback({
toObj: instanceValues,
fromObj: instanceSettings,
defaultsObj: bridge.getInstanceDefaults(),
keys: [
"prehidingStyle",
"targetMigrationEnabled",
"personalizationStorageEnabled"
"personalizationStorageEnabled",
"autoTrackPropositionInteractions"
]
});

Expand All @@ -55,10 +66,17 @@ export const bridge = {
keys: [
"prehidingStyle",
"targetMigrationEnabled",
"personalizationStorageEnabled"
"personalizationStorageEnabled",
"autoTrackPropositionInteractions"
]
});

if (instanceSettings.autoTrackPropositionInteractions) {
instanceSettings.autoTrackPropositionInteractions = {
AJO: instanceValues.autoTrackPropositionInteractions
};
}

return instanceSettings;
}
};
Expand Down Expand Up @@ -108,6 +126,26 @@ const PersonalizationSection = ({ instanceFieldName }) => {
>
Enable personalization storage <BetaBadge />
</FormikCheckbox>
<FormikRadioGroup
name={`${instanceFieldName}.autoTrackPropositionInteractions`}
label="Auto-track proposition interactions for Adobe Journey Optimizer"
description="This controls whether the Web SDK automatically tracks interactions with propositions from Adobe Journey Optimizer."
width="size-5000"
>
<Radio value="always" data-test-id="alwaysOption">
Always - Track all interactions with propositions.
</Radio>
<Radio
value="decoratedElementsOnly"
data-test-id="decoratedElementsOnlyOption"
>
Decorated elements only - Only track interactions on elements with
data-aep-click-label or data-aep-click-token attributes.
</Radio>
<Radio value="never" data-test-id="neverOption">
Never - Do not track interactions with propositions.
</Radio>
</FormikRadioGroup>
</FormElementContainer>
</>
);
Expand Down
18 changes: 11 additions & 7 deletions src/view/forms/radioGroup.jsx
Expand Up @@ -54,7 +54,8 @@ export default function radioGroup({
items,
defaultValue = "",
description,
beta
beta,
orientation = "vertical"
}) {
const validationShape = {};
if (isRequired) {
Expand All @@ -81,12 +82,14 @@ export default function radioGroup({
getInitialValues({ initInfo }) {
const { [name]: value = defaultValue } = initInfo.settings || {};
const initialValues = {
[name]: value,
[`${name}DataElement`]: ""
[name]: value
};
if (value.match(singleDataElementRegex)) {
initialValues[`${name}DataElement`] = value;
initialValues[name] = "dataElement";
if (dataElementSupported) {
initialValues[`${name}DataElement`] = "";
if (value.match(singleDataElementRegex)) {
initialValues[`${name}DataElement`] = value;
initialValues[name] = "dataElement";
}
}
return initialValues;
},
Expand All @@ -106,11 +109,12 @@ export default function radioGroup({
<>
<FormikRadioGroup
data-test-id={`${namePrefix}${name}Field`}
name={name}
name={`${namePrefix}${name}`}
label={labelElement}
isRequired={isRequired}
width="size-5000"
description={description}
orientation={orientation}
>
<>
{items.map(item => (
Expand Down
5 changes: 3 additions & 2 deletions src/view/forms/textField.jsx
Expand Up @@ -36,7 +36,8 @@ export default function textField({
label,
description,
width = "size-5000",
validationSchemaBase = string()
validationSchemaBase = string(),
ariaLabel = label
}) {
let validationSchema = validationSchemaBase;
if (isRequired) {
Expand All @@ -57,7 +58,7 @@ export default function textField({
data-test-id={`${namePrefix}${name}TextField`}
name={`${namePrefix}${name}`}
label={hideLabel ? undefined : label}
aria-label={label}
aria-label={ariaLabel}
isRequired={isRequired}
description={description}
width={width}
Expand Down

0 comments on commit 64fe904

Please sign in to comment.