Skip to content

Commit

Permalink
In browser messages (#1029)
Browse files Browse the repository at this point in the history
* messaging action modules

* banner test

* modal test

* decisioning engine component

* fix test

* removed modulesProvider and refactored it into actionsProvider with an executeAction method

* license headers

* license headers

* introduced context provider for managing context

* license header

* introduced context provider for managing context

* license header

* message feed POC

* added some tests.

* track display/interact events and save to storage

* limit event storage

* store decision history as object

* decisioning.qualifiedItem event

* refactor event registry a little

* provide collect function to messaging actions

* fix package-lock.json

* fix debounce test

* applyResponse initialized once

* CJM-45417-globalDecisionContext (#986)

* Setting global decisionContext with data like current date/time, date/time page loaded, browser name/version, scroll position, etc

* update time and window context on each getContext call, parse url using lib
Todo: fix unit tests, add more tests and flattenObject

* dependency

* code refactoring based on code review

* add-license

* include the package-lock.json file in the pull request

* pass in userAgent in custom window object

* mock to ensure that the date remains the same across different timezones

* flattening the context object so that rules can apply

* test to check if flattening is applied and rules conditions are met for onDecision with propositions to be called

* applied fix

* a little structured tests

* following convention

* evaluates global contexts

* tests breakdown

* tests

* test global context separately

* context flattened

* mocking time, Jasmine clock does not inherently take into account different time zones

* reverted  redundant tests from other files

* flattenObject only needs to be called once.

* narrowed the scope of the test for specificity

* Revert "narrowed the scope of the test for specificity"

This reverts commit 3939b61.

* narrowed the scope of the test for specificity

* extracted reused methods

* unit test for renderDecisions command

* add license

* run for all the browser with renderDecisions

* validate a global context with command

* validate a global context with command

* always index rulesets

---------

Co-authored-by: Jason Waters <[email protected]>

* don't flatten events on context

* [CJM-48525]Renamed renderDecision command to evaluateRulesets (#994)

* renamed renderDecision to evaluateRulesets

* renamed renderDecision to evaluateRulesets fix typo

* evaluateRulesets

* added consequence adapter and refactored iframe display code

* license

* [CJM-48522]Purge historical events post retention period (#997)

* purge historical events post retention period

* fixed fragile test

* defensively check for ruleset items

* update to schema based actions

* update schemas

* rename json-ruleset-item to ruleset-item

* rename in-app message schema

* Dismiss Messages & url click (#1024)

* Ui parameter bug fix
Added Nonce to script

* better styling

* demo ready

* sandbox demo

* added unit test for buildStyleFromParameters

* unit test

* remove existing modal and overlay before displaying

* remove existing modal and overlay before displaying

* url click

* test

* clean up dom

* more test

* renamed to InAppMessages for sandbox demo

* code refactoring based on review comments

* test for script tag nonce

* transformPayload removed from alloy sandbox, it is taken care on the backend side

* test fix

---------

Co-authored-by: Jason Waters <[email protected]>

* rename qualified event to decisioning.propositionQualified

* fix test

* subscribeRulesetItems command

* license

* remove IAM types, add message feed actions modules

* license

* ensure schema based ruleset consequences

* message feed sandbox (#1028)

* message feed sandbox

* fixed eslint for InApp demo

* clear local storage and reload the page

* support "Send data to platform" trigger (#1030)

* [CJM-46521] Send interact events when in-app messages are clicked (#1031)

* Send interact events when in-app messages are clicked

* update sandbox

* evaluateRulesetsCommand (#1033)

* functional tests (#1034)

* tests

* to debug issue in sauce lab

* rephrased

* clean up

* web parameters support (#1035)

* web parameters support
removed redundant files & some clean up

* code refactoring

* adding test for web parameteres

* code refactoring based on review

* webProperties (#1039)

* webProperties

* webProperties

* improve isValidWebParameters

---------

Co-authored-by: Jason Waters <[email protected]>
Co-authored-by: Jason Waters <[email protected]>

* support "~timestampu" and  "~timestampz" (#1044)

* support "~imestampu" and  "~timestampz"

* support ~sdkver - the current Adobe Experience Platform SDKs version string.

* use existing libraryVersion

* keeping package-lock.json untouched.

* In browser messages e2e (#1045)

* updated demo to use web IAM campaign on stage

* fixed header

* update adapters for latest schema based items

* add custom trait to demo page

* allow choose environment

* resolve config warning on iam demo page

* support manual triggers

* remove surface designation on IAM sandbox demo

* clear cookies when switching demo environment

* Historical events fix (#1051)

* save payloads based on activityId

* CJM-53824

* right keys for the day and hour

* corrected payload

* npm link to local rule engine, will change to the deployed version before merging

* saved by activityId in the local storage

* constants shared between the two components src/constants

* using v2.0.2 of ruleEngine to support historical search

* fix for click through (#1054)

* Code Review Fixes  (#1052)

* use existing Alloy DOM utils

* removed unused utils method

* renamed to "test:unit:debug"

* added a try/catch to  handle potential JSON parsing errors

* removed ensureSchemaBasedRulesetConsequences

* using shorthand object property notation

* new line

* constants shared between components moved to the shared src/constants module

* use alloy utils method includes

* use alloy utils method values, objectOf

* lint

* removeElementById for readability

---------

Co-authored-by: Jason Waters <[email protected]>

* IAM: support multiple subscriptions (#1059)

* support multi-subscription

* support multi-subscription

* remove mobile app fudge

* support distinct emissions for each subscription with conditions

* event.hasQuery()

* values()

* rename mobile events

* Consent & local storage config flag (#1064)

* config flag to enable storage in localStorage

* based on consent set event registry

* tests

* for sandbox testing

* fix after test

* in-memory storage

* tests

* utils tests

* use setStorage only

---------

Co-authored-by: Jason Waters <[email protected]>

* remove message-feed (#1065)

* Move decisionContext within personalization (#1068)

* few test (#1067)

* few test

* few test

* few test

* fix test

* code review fix (#1069)

* using selectNodes, isNonEmptyArray, isNonEmptyString utils

* using toArray

* using createRedirect

* using warning instead of error

* some fixes (#1071)

* remove ALLOY from constants

---------

Co-authored-by: Happy Shandilya <[email protected]>
  • Loading branch information
jasonwaters and shandilya3 authored Oct 27, 2023
1 parent 256b178 commit 23eb053
Show file tree
Hide file tree
Showing 123 changed files with 9,280 additions and 65 deletions.
42 changes: 42 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"format": "prettier --write \"*.{html,js}\" \"{sandbox,src,test,scripts}/**/*.{html,js}\"",
"test": "npm run test:unit && npm run test:scripts && npm run test:functional",
"test:unit": "karma start --single-run",
"test:unit:debug": "karma start --browsers=Chrome --single-run=false --debug",
"test:unit:watch": "karma start",
"test:unit:saucelabs:local": "karma start karma.saucelabs.conf.js --single-run",
"test:unit:coverage": "karma start --single-run --reporters spec,coverage",
Expand Down Expand Up @@ -58,11 +59,14 @@
}
],
"dependencies": {
"@adobe/aep-rules-engine": "^2.0.2",
"@adobe/reactor-cookie": "^1.0.0",
"@adobe/reactor-load-script": "^1.1.1",
"@adobe/reactor-object-assign": "^1.0.0",
"@adobe/reactor-query-string": "^1.0.0",
"css.escape": "^1.5.1",
"js-cookie": "2.2.1",
"parse-uri": "^1.0.7",
"uuid": "^3.3.2"
},
"devDependencies": {
Expand Down
2 changes: 1 addition & 1 deletion sandbox/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
!function(n,o){o.forEach(function(o){n[o]||((n.__alloyNS=n.__alloyNS||
[]).push(o),n[o]=function(){var u=arguments;return new Promise(
function(i,l){n[o].q.push([i,l,u])})},n[o].q=[])})}
(window,["alloy", "organizationTwo", "cjmProd"]);
(window,["alloy", "organizationTwo", "cjmProd", 'iamAlloy']);
</script>

<script nonce="%REACT_APP_NONCE%">
Expand Down
5 changes: 5 additions & 0 deletions sandbox/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import PersonalizationFormBased from "./PersonalizationFormBased";
import Identity from "./Identity";
import AlloyVersion from "./components/AlloyVersion";
import ConfigOverrides from "./ConfigOverrides.jsx";
import InAppMessages from "./components/InAppMessagesDemo/InAppMessages";

const BasicExample = () => {
return (
Expand Down Expand Up @@ -96,6 +97,9 @@ const BasicExample = () => {
<li>
<a href="/configOverrides">Config Overrides</a>
</li>
<li>
<Link to="/inAppMessages">In-app Messages</Link>
</li>
</ul>
<hr />

Expand Down Expand Up @@ -125,6 +129,7 @@ const BasicExample = () => {
<Route path="/redirectedNewPage" component={RedirectedNewPage} />
<Route path="/identity" component={Identity} />
<Route path="/configOverrides" component={ConfigOverrides} />
<Route path="/inAppMessages" component={InAppMessages} />
</div>
</Router>
<AlloyVersion />
Expand Down
2 changes: 1 addition & 1 deletion sandbox/src/components/ContentSecurityPolicy.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export default function ContentSecurityPolicy() {
http-equiv="Content-Security-Policy"
// cdn.tt.omtrdc.net is necessary for Target VEC to function properly.
// *.sc.omtrdc.net is necessary for Analytics Data Insertion API to function properly
content={`default-src 'self';
content={`default-src 'self' blob:;
script-src 'self' 'nonce-${process.env.REACT_APP_NONCE}' cdn.jsdelivr.net assets.adobedtm.com cdn.tt.omtrdc.net;
style-src 'self' 'unsafe-inline';
img-src * data:;
Expand Down
163 changes: 163 additions & 0 deletions sandbox/src/components/InAppMessagesDemo/InAppMessages.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
/* eslint-disable no-bitwise, no-console */
import React, { useEffect, useState } from "react";
import ContentSecurityPolicy from "../ContentSecurityPolicy";
import "./InAppMessagesStyle.css";

const configKey = localStorage.getItem("iam-configKey") || "stage";

const config = {
cjmProdNld2: {
name: "CJM Prod NLD2 – Prod (NLD2)",
alloyInstance: window.alloy,
datastreamId: "7a19c434-6648-48d3-948f-ba0258505d98",
orgId: "4DA0571C5FDC4BF70A495FC2@AdobeOrg",
decisionContext: {},
edgeDomain: "edge.adobedc.net"
},
aemonacpprodcampaign: {
name: "AEM Assets Departmental - Campaign – Prod (VA7)",
alloyInstance: window.iamAlloy,
datastreamId: "8cefc5ca-1c2a-479f-88f2-3d42cc302514",
orgId: "906E3A095DC834230A495FD6@AdobeOrg",
decisionContext: {},
edgeDomain: "edge.adobedc.net"
},
stage: {
name: "CJM Stage - AJO Web (VA7)",
alloyInstance: window.iamAlloy,
datastreamId: "15525167-fd4e-4511-b9e0-02119485784f",
orgId: "745F37C35E4B776E0A49421B@AdobeOrg",
decisionContext: {},
edgeDomain: "edge-int.adobedc.net"
}
};

const {
datastreamId,
orgId,
decisionContext,
edgeDomain,
alloyInstance
} = config[configKey];

const getURLParams = key => {
const urlParams = new URLSearchParams(window.location.search);
return urlParams.get(key);
};

if (alloyInstance !== window.alloy) {
alloyInstance("configure", {
defaultConsent: getURLParams("defaultConsent") || "in",
datastreamId,
orgId,
edgeDomain,
thirdPartyCookiesEnabled: false,
targetMigrationEnabled: false,
debugEnabled: true
});
}

export default function InAppMessages() {
const [sentEvent, setSentEvent] = useState(false);
const [customTraitKey, setCustomTraitKey] = useState("");
const [customTraitValue, setCustomTraitValue] = useState("");

useEffect(() => {
const unsubscribePromise = alloyInstance("subscribeRulesetItems", {
callback: result => {
console.log("subscribeRulesetItems", result);
}
});

return () => {
unsubscribePromise.then(({ unsubscribe }) => unsubscribe());
};
}, []);

const renderDecisions = (useEvaluateRulesetsCommand = false) => {
const context = { ...decisionContext };

if (customTraitKey.length !== 0 && customTraitValue.length !== 0) {
context[customTraitKey] = customTraitValue;
}

if (useEvaluateRulesetsCommand) {
alloyInstance("evaluateRulesets", {
renderDecisions: true,
personalization: {
decisionContext: context
}
});
return;
}

alloyInstance("sendEvent", {
renderDecisions: true,
personalization: { surfaces: ["#hello"], decisionContext: context }
}).then(() => setSentEvent(true));
};

const deleteAllCookies = () => {
const cookies = document.cookie.split(";");

for (let i = 0; i < cookies.length; i += 1) {
const cookie = cookies[i];
const eqPos = cookie.indexOf("=");
const name = eqPos > -1 ? cookie.substr(0, eqPos) : cookie;
document.cookie = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 GMT`;
}
};

const setNewConfigEnv = value => {
localStorage.setItem("iam-configKey", value);
deleteAllCookies();
window.location.reload();
};

return (
<div>
<ContentSecurityPolicy />
<h1>In App Messages For Web</h1>
<div>
<label htmlFor="cars">Environment:</label>
<select
id="configEnv"
name="configEnv"
onChange={evt => setNewConfigEnv(evt.target.value)}
defaultValue={configKey}
>
{Object.keys(config).map(conf => (
<option key={conf} value={conf}>
{config[conf].name}
</option>
))}
</select>
<div style={{ marginBottom: "20px" }}>
<h3>Custom Trait</h3>
<span style={{ marginRight: "20px" }}>
<label htmlFor="input-custom-trait-key">Key</label>
<input
id="input-custom-trait-key"
type="text"
value={customTraitKey}
onChange={evt => setCustomTraitKey(evt.target.value)}
/>
</span>
<span style={{ marginRight: "20px" }}>
<label htmlFor="input-custom-trait-value">Value</label>
<input
id="input-custom-trait-value"
type="text"
value={customTraitValue}
onChange={evt => setCustomTraitValue(evt.target.value)}
/>
</span>
</div>
<button onClick={() => renderDecisions()}>sendEvent</button>
<button onClick={() => renderDecisions(true)} disabled={!sentEvent}>
evaluateRulesets
</button>
</div>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.custom-heading {
color: red;
font-size: 25px;
}
.element-spacing {
margin-right: 10px;
}
2 changes: 2 additions & 0 deletions src/components/DataCollector/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ const createDataCollector = ({ eventManager, logger }) => {
run: options => {
const {
renderDecisions = false,
decisionContext = {},
responseHeaders = {},
responseBody = { handle: [] },
personalization
Expand All @@ -89,6 +90,7 @@ const createDataCollector = ({ eventManager, logger }) => {

return eventManager.applyResponse(event, {
renderDecisions,
decisionContext,
responseHeaders,
responseBody,
personalization
Expand Down
3 changes: 2 additions & 1 deletion src/components/DataCollector/validateApplyResponse.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ export default ({ options }) => {
).required()
}).required(),
personalization: objectOf({
sendDisplayEvent: boolean().default(true)
sendDisplayEvent: boolean().default(true),
decisionContext: objectOf({})
}).default({ sendDisplayEvent: true })
}).noUnknownFields();

Expand Down
3 changes: 2 additions & 1 deletion src/components/DataCollector/validateUserEventOptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ export default ({ options }) => {
surfaces: arrayOf(string()).uniqueItems(),
sendDisplayEvent: boolean().default(true),
includeRenderedPropositions: boolean().default(false),
requestPersonalization: boolean()
requestPersonalization: boolean(),
decisionContext: objectOf({})
}).default({ sendDisplayEvent: true }),
datasetId: string(),
mergeId: string(),
Expand Down
Loading

0 comments on commit 23eb053

Please sign in to comment.