diff --git a/.changeset/every-ravens-look.md b/.changeset/every-ravens-look.md new file mode 100644 index 000000000..a204bdc12 --- /dev/null +++ b/.changeset/every-ravens-look.md @@ -0,0 +1,5 @@ +--- +"@adobe/alloy": patch +--- + +Passes inbox item after user subscribes to ruleset items diff --git a/packages/core/src/components/Personalization/createPersonalizationDetails.js b/packages/core/src/components/Personalization/createPersonalizationDetails.js index ca3d6c843..94f7a0ccc 100644 --- a/packages/core/src/components/Personalization/createPersonalizationDetails.js +++ b/packages/core/src/components/Personalization/createPersonalizationDetails.js @@ -21,6 +21,7 @@ import { REDIRECT_ITEM, RULESET_ITEM, MESSAGE_CONTENT_CARD, + INBOX_ITEM, } from "../../constants/schema.js"; import { buildPageSurface, @@ -102,6 +103,7 @@ export default ({ RULESET_ITEM, MESSAGE_IN_APP, MESSAGE_CONTENT_CARD, + INBOX_ITEM, ]; if (scopes.includes(PAGE_WIDE_SCOPE)) { diff --git a/packages/core/src/components/RulesEngine/createOnResponseHandler.js b/packages/core/src/components/RulesEngine/createOnResponseHandler.js index 6fbfbac84..bd928107c 100644 --- a/packages/core/src/components/RulesEngine/createOnResponseHandler.js +++ b/packages/core/src/components/RulesEngine/createOnResponseHandler.js @@ -10,9 +10,18 @@ OF ANY KIND, either express or implied. See the License for the specific languag governing permissions and limitations under the License. */ +import { INBOX_ITEM } from "../../constants/schema.js"; import { PERSONALIZATION_DECISIONS_HANDLE } from "../../constants/decisionProvider.js"; import flattenObject from "../../utils/flattenObject.js"; +const extractInboxPropositions = (payloads) => + payloads.filter( + (payload) => + Array.isArray(payload.items) && + payload.items.length > 0 && + payload.items.every((item) => item.schema === INBOX_ITEM), + ); + export default ({ renderDecisions, decisionProvider, @@ -27,16 +36,20 @@ export default ({ }; return ({ response }) => { - decisionProvider.addPayloads( - response.getPayloadsByType(PERSONALIZATION_DECISIONS_HANDLE), + const personalizationPayloads = response.getPayloadsByType( + PERSONALIZATION_DECISIONS_HANDLE, ); + decisionProvider.addPayloads(personalizationPayloads); // only evaluate events that include a personalization query if (!event.hasQuery()) { return { propositions: [] }; } - const propositions = decisionProvider.evaluate(context); + const inboxPropositions = extractInboxPropositions(personalizationPayloads); + + const evaluatedPropositions = decisionProvider.evaluate(context); + const propositions = [...evaluatedPropositions, ...inboxPropositions]; return applyResponse({ renderDecisions, diff --git a/packages/core/src/constants/schema.js b/packages/core/src/constants/schema.js index 2df5c5546..f559a89f5 100644 --- a/packages/core/src/constants/schema.js +++ b/packages/core/src/constants/schema.js @@ -18,6 +18,7 @@ export const HTML_CONTENT_ITEM = export const JSON_CONTENT_ITEM = "https://ns.adobe.com/personalization/json-content-item"; export const RULESET_ITEM = "https://ns.adobe.com/personalization/ruleset-item"; +export const INBOX_ITEM = "https://ns.adobe.com/personalization/inbox-item"; export const REDIRECT_ITEM = "https://ns.adobe.com/personalization/redirect-item"; diff --git a/packages/core/test/unit/specs/components/Personalization/createPersonalizationDetails.spec.js b/packages/core/test/unit/specs/components/Personalization/createPersonalizationDetails.spec.js index 21bbad23c..f13879824 100644 --- a/packages/core/test/unit/specs/components/Personalization/createPersonalizationDetails.spec.js +++ b/packages/core/test/unit/specs/components/Personalization/createPersonalizationDetails.spec.js @@ -22,6 +22,7 @@ import { REDIRECT_ITEM, RULESET_ITEM, MESSAGE_CONTENT_CARD, + INBOX_ITEM, } from "../../../../../src/constants/schema.js"; describe("Personalization::createPersonalizationDetails", () => { @@ -162,6 +163,7 @@ describe("Personalization::createPersonalizationDetails", () => { RULESET_ITEM, MESSAGE_IN_APP, MESSAGE_CONTENT_CARD, + INBOX_ITEM, DOM_ACTION, ], decisionScopes: expectedDecisionScopes, @@ -201,6 +203,7 @@ describe("Personalization::createPersonalizationDetails", () => { RULESET_ITEM, MESSAGE_IN_APP, MESSAGE_CONTENT_CARD, + INBOX_ITEM, DOM_ACTION, ], decisionScopes: expectedDecisionScopes, @@ -240,6 +243,7 @@ describe("Personalization::createPersonalizationDetails", () => { RULESET_ITEM, MESSAGE_IN_APP, MESSAGE_CONTENT_CARD, + INBOX_ITEM, DOM_ACTION, ], decisionScopes: expectedDecisionScopes, @@ -279,6 +283,7 @@ describe("Personalization::createPersonalizationDetails", () => { RULESET_ITEM, MESSAGE_IN_APP, MESSAGE_CONTENT_CARD, + INBOX_ITEM, ], decisionScopes: expectedDecisionScopes, surfaces: [], @@ -319,6 +324,7 @@ describe("Personalization::createPersonalizationDetails", () => { RULESET_ITEM, MESSAGE_IN_APP, MESSAGE_CONTENT_CARD, + INBOX_ITEM, ], decisionScopes: expectedDecisionScopes, surfaces: ["web://test1.com/"], @@ -360,6 +366,7 @@ describe("Personalization::createPersonalizationDetails", () => { RULESET_ITEM, MESSAGE_IN_APP, MESSAGE_CONTENT_CARD, + INBOX_ITEM, ], decisionScopes: expectedDecisionScopes, surfaces: ["web://test1.com/"], @@ -487,6 +494,7 @@ describe("Personalization::createPersonalizationDetails", () => { RULESET_ITEM, MESSAGE_IN_APP, MESSAGE_CONTENT_CARD, + INBOX_ITEM, DOM_ACTION, ], decisionScopes: expectedDecisionScopes, diff --git a/packages/core/test/unit/specs/components/Personalization/topLevel/cartViewDecisions.spec.js b/packages/core/test/unit/specs/components/Personalization/topLevel/cartViewDecisions.spec.js index c0795fa41..c6b9773e7 100644 --- a/packages/core/test/unit/specs/components/Personalization/topLevel/cartViewDecisions.spec.js +++ b/packages/core/test/unit/specs/components/Personalization/topLevel/cartViewDecisions.spec.js @@ -37,6 +37,7 @@ describe("PersonalizationComponent", () => { "https://ns.adobe.com/personalization/ruleset-item", "https://ns.adobe.com/personalization/message/in-app", "https://ns.adobe.com/personalization/message/content-card", + "https://ns.adobe.com/personalization/inbox-item", "https://ns.adobe.com/personalization/dom-action", ], decisionScopes: ["__view__"], @@ -172,6 +173,7 @@ describe("PersonalizationComponent", () => { "https://ns.adobe.com/personalization/ruleset-item", "https://ns.adobe.com/personalization/message/in-app", "https://ns.adobe.com/personalization/message/content-card", + "https://ns.adobe.com/personalization/inbox-item", "https://ns.adobe.com/personalization/dom-action", ], decisionScopes: ["__view__"], diff --git a/packages/core/test/unit/specs/components/Personalization/topLevel/mergedMetricDecisions.spec.js b/packages/core/test/unit/specs/components/Personalization/topLevel/mergedMetricDecisions.spec.js index b1e631360..53ed30605 100644 --- a/packages/core/test/unit/specs/components/Personalization/topLevel/mergedMetricDecisions.spec.js +++ b/packages/core/test/unit/specs/components/Personalization/topLevel/mergedMetricDecisions.spec.js @@ -35,6 +35,7 @@ describe("PersonalizationComponent", () => { "https://ns.adobe.com/personalization/ruleset-item", "https://ns.adobe.com/personalization/message/in-app", "https://ns.adobe.com/personalization/message/content-card", + "https://ns.adobe.com/personalization/inbox-item", "https://ns.adobe.com/personalization/dom-action", ], decisionScopes: ["__view__"], diff --git a/packages/core/test/unit/specs/components/Personalization/topLevel/mixedPropositions.spec.js b/packages/core/test/unit/specs/components/Personalization/topLevel/mixedPropositions.spec.js index 95c0ffb2a..5eb0eebdf 100644 --- a/packages/core/test/unit/specs/components/Personalization/topLevel/mixedPropositions.spec.js +++ b/packages/core/test/unit/specs/components/Personalization/topLevel/mixedPropositions.spec.js @@ -38,6 +38,7 @@ describe("PersonalizationComponent", () => { "https://ns.adobe.com/personalization/ruleset-item", "https://ns.adobe.com/personalization/message/in-app", "https://ns.adobe.com/personalization/message/content-card", + "https://ns.adobe.com/personalization/inbox-item", "https://ns.adobe.com/personalization/dom-action", ], decisionScopes: ["__view__"], diff --git a/packages/core/test/unit/specs/components/Personalization/topLevel/pageWideDecisionsWithDomActionSchemaItems.spec.js b/packages/core/test/unit/specs/components/Personalization/topLevel/pageWideDecisionsWithDomActionSchemaItems.spec.js index 5093dbd5f..cdac0e8ea 100644 --- a/packages/core/test/unit/specs/components/Personalization/topLevel/pageWideDecisionsWithDomActionSchemaItems.spec.js +++ b/packages/core/test/unit/specs/components/Personalization/topLevel/pageWideDecisionsWithDomActionSchemaItems.spec.js @@ -36,6 +36,7 @@ describe("PersonalizationComponent", () => { "https://ns.adobe.com/personalization/ruleset-item", "https://ns.adobe.com/personalization/message/in-app", "https://ns.adobe.com/personalization/message/content-card", + "https://ns.adobe.com/personalization/inbox-item", "https://ns.adobe.com/personalization/dom-action", ], decisionScopes: ["__view__"], diff --git a/packages/core/test/unit/specs/components/Personalization/topLevel/pageWideScopeDecisions.spec.js b/packages/core/test/unit/specs/components/Personalization/topLevel/pageWideScopeDecisions.spec.js index a2623925b..4c22ad806 100644 --- a/packages/core/test/unit/specs/components/Personalization/topLevel/pageWideScopeDecisions.spec.js +++ b/packages/core/test/unit/specs/components/Personalization/topLevel/pageWideScopeDecisions.spec.js @@ -37,6 +37,7 @@ describe("PersonalizationComponent", () => { "https://ns.adobe.com/personalization/ruleset-item", "https://ns.adobe.com/personalization/message/in-app", "https://ns.adobe.com/personalization/message/content-card", + "https://ns.adobe.com/personalization/inbox-item", "https://ns.adobe.com/personalization/dom-action", ], decisionScopes: ["__view__"], diff --git a/packages/core/test/unit/specs/components/Personalization/topLevel/pageWideScopeDecisionsWithoutDomActionSchemaItems.spec.js b/packages/core/test/unit/specs/components/Personalization/topLevel/pageWideScopeDecisionsWithoutDomActionSchemaItems.spec.js index e4c644292..a3d75e436 100644 --- a/packages/core/test/unit/specs/components/Personalization/topLevel/pageWideScopeDecisionsWithoutDomActionSchemaItems.spec.js +++ b/packages/core/test/unit/specs/components/Personalization/topLevel/pageWideScopeDecisionsWithoutDomActionSchemaItems.spec.js @@ -37,6 +37,7 @@ describe("PersonalizationComponent", () => { "https://ns.adobe.com/personalization/ruleset-item", "https://ns.adobe.com/personalization/message/in-app", "https://ns.adobe.com/personalization/message/content-card", + "https://ns.adobe.com/personalization/inbox-item", "https://ns.adobe.com/personalization/dom-action", ], decisionScopes: ["__view__"], diff --git a/packages/core/test/unit/specs/components/Personalization/topLevel/productsViewDecisions.spec.js b/packages/core/test/unit/specs/components/Personalization/topLevel/productsViewDecisions.spec.js index 666dafa24..b287b866a 100644 --- a/packages/core/test/unit/specs/components/Personalization/topLevel/productsViewDecisions.spec.js +++ b/packages/core/test/unit/specs/components/Personalization/topLevel/productsViewDecisions.spec.js @@ -35,6 +35,7 @@ describe("PersonalizationComponent", () => { "https://ns.adobe.com/personalization/ruleset-item", "https://ns.adobe.com/personalization/message/in-app", "https://ns.adobe.com/personalization/message/content-card", + "https://ns.adobe.com/personalization/inbox-item", "https://ns.adobe.com/personalization/dom-action", ], decisionScopes: ["__view__"], diff --git a/packages/core/test/unit/specs/components/Personalization/topLevel/redirectPageWideScopeDecision.spec.js b/packages/core/test/unit/specs/components/Personalization/topLevel/redirectPageWideScopeDecision.spec.js index 8f9bddc91..f9bc166e3 100644 --- a/packages/core/test/unit/specs/components/Personalization/topLevel/redirectPageWideScopeDecision.spec.js +++ b/packages/core/test/unit/specs/components/Personalization/topLevel/redirectPageWideScopeDecision.spec.js @@ -35,6 +35,7 @@ describe("PersonalizationComponent", () => { "https://ns.adobe.com/personalization/ruleset-item", "https://ns.adobe.com/personalization/message/in-app", "https://ns.adobe.com/personalization/message/content-card", + "https://ns.adobe.com/personalization/inbox-item", "https://ns.adobe.com/personalization/dom-action", ], decisionScopes: ["__view__"], diff --git a/packages/core/test/unit/specs/components/Personalization/topLevel/scopesFoo1Foo2Decisions.spec.js b/packages/core/test/unit/specs/components/Personalization/topLevel/scopesFoo1Foo2Decisions.spec.js index 44d91ab9c..b82436332 100644 --- a/packages/core/test/unit/specs/components/Personalization/topLevel/scopesFoo1Foo2Decisions.spec.js +++ b/packages/core/test/unit/specs/components/Personalization/topLevel/scopesFoo1Foo2Decisions.spec.js @@ -35,6 +35,7 @@ describe("PersonalizationComponent", () => { "https://ns.adobe.com/personalization/ruleset-item", "https://ns.adobe.com/personalization/message/in-app", "https://ns.adobe.com/personalization/message/content-card", + "https://ns.adobe.com/personalization/inbox-item", "https://ns.adobe.com/personalization/dom-action", ], decisionScopes: ["__view__"], diff --git a/packages/core/test/unit/specs/components/RulesEngine/createDecisionProvider.spec.js b/packages/core/test/unit/specs/components/RulesEngine/createDecisionProvider.spec.js index 88c6d22d0..e7a346922 100644 --- a/packages/core/test/unit/specs/components/RulesEngine/createDecisionProvider.spec.js +++ b/packages/core/test/unit/specs/components/RulesEngine/createDecisionProvider.spec.js @@ -444,27 +444,42 @@ describe("RulesEngine:createDecisionProvider", () => { }, ]); }); - it("ignores payloads that aren't json-ruleset type", () => { - decisionProvider.addPayload({ + it("does not add payloads that contain only inbox items (handled in response handler)", () => { + const inboxPayload = { + id: "66e05490-5e91-45c4-8eee-339784032940", + scope: "mobileapp://com.app/trendingnow", + scopeDetails: { + decisionProvider: "AJO", + activity: { id: "99db8aff4-82af-460e-8524-73e1441afdfa#id" }, + }, + items: [ + { + id: "569d1166-d3e0-4aea-b9a7-6de8ebdf3aec", + schema: "https://ns.adobe.com/personalization/inbox-item", + data: { + content: { + heading: { content: "Trending Now Inbox" }, + layout: { orientation: "horizontal" }, + capacity: 10, + }, + }, + }, + ], + }; + decisionProvider.addPayload(inboxPayload); + expect(decisionProvider.evaluate()).toEqual([]); + }); + + it("does not add payloads that have items but no inbox or ruleset items (e.g. TGT dom-action only)", () => { + const tgtPayload = { id: "AT:eyJhY3Rpdml0eUlkIjoiMTQxMDY0IiwiZXhwZXJpZW5jZUlkIjoiMCJ9", scope: "__view__", scopeDetails: { decisionProvider: "TGT", - activity: { - id: "141064", - }, - experience: { - id: "0", - }, - strategies: [ - { - algorithmID: "0", - trafficType: "0", - }, - ], - characteristics: { - eventToken: "abc", - }, + activity: { id: "141064" }, + experience: { id: "0" }, + strategies: [{ algorithmID: "0", trafficType: "0" }], + characteristics: { eventToken: "abc" }, correlationID: "141064:0:0:0", }, items: [ @@ -480,7 +495,8 @@ describe("RulesEngine:createDecisionProvider", () => { }, }, ], - }); + }; + decisionProvider.addPayload(tgtPayload); expect(decisionProvider.evaluate()).toEqual([]); }); }); diff --git a/packages/core/test/unit/specs/components/RulesEngine/createOnResponseHandler.spec.js b/packages/core/test/unit/specs/components/RulesEngine/createOnResponseHandler.spec.js index d434d18fe..ff5093b7b 100644 --- a/packages/core/test/unit/specs/components/RulesEngine/createOnResponseHandler.spec.js +++ b/packages/core/test/unit/specs/components/RulesEngine/createOnResponseHandler.spec.js @@ -396,4 +396,65 @@ describe("RulesEngine:createOnResponseHandler", () => { identityMap: undefined, }); }); + + it("converts inbox-only payloads to propositions and passes them to applyResponse with evaluated propositions", () => { + const event = { + getViewName: () => undefined, + getUserIdentityMap: () => undefined, + hasQuery: () => true, + getContent: () => ({ query: {}, xdm: {}, data: {} }), + }; + const responseHandler = createOnResponseHandler({ + renderDecisions: true, + decisionProvider, + applyResponse, + event, + personalization: {}, + decisionContext: {}, + }); + const inboxPayload = { + id: "66e05490-5e91-45c4-8eee-339784032940", + scope: "mobileapp://com.app/trendingnow", + scopeDetails: { + decisionProvider: "AJO", + activity: { id: "99db8aff4-82af-460e-8524-73e1441afdfa#id" }, + }, + items: [ + { + id: "569d1166-d3e0-4aea-b9a7-6de8ebdf3aec", + schema: "https://ns.adobe.com/personalization/inbox-item", + data: { + content: { + heading: { content: "Trending Now Inbox" }, + capacity: 10, + }, + }, + }, + ], + }; + const response = { + getPayloadsByType: () => [inboxPayload], + }; + responseHandler({ response }); + expect(lifecycle.onDecision).toHaveBeenCalledWith( + expect.objectContaining({ + propositions: [ + expect.objectContaining({ + id: inboxPayload.id, + items: [ + expect.objectContaining({ + schema: "https://ns.adobe.com/personalization/inbox-item", + data: expect.objectContaining({ + content: { + heading: { content: "Trending Now Inbox" }, + capacity: 10, + }, + }), + }), + ], + }), + ], + }), + ); + }); }); diff --git a/sandboxes/browser/src/App.jsx b/sandboxes/browser/src/App.jsx index 648c33b59..0f82bd7cf 100755 --- a/sandboxes/browser/src/App.jsx +++ b/sandboxes/browser/src/App.jsx @@ -32,6 +32,7 @@ import AlloyVersion from "./components/AlloyVersion"; import ConfigOverrides from "./ConfigOverrides"; import InAppMessages from "./components/InAppMessagesDemo/InAppMessages"; import ContentCards from "./components/ContentCardsDemo/ContentCards"; +import MessageInbox from "./components/MessageInboxDemo/MessageInbox"; import PushNotifications from "./PushNotifications"; import ReferrerTest from "./ReferrerTest"; import Advertising from "./Advertising"; @@ -108,6 +109,9 @@ const BasicExample = () => {
+ This page demonstrates a "message inbox" fed by content cards + and configured by an inbox-item. Open the inbox to see messages from + this session; use the buttons below to add mock messages. +
+ + + +{toast.title}
+{toast.body}
++ Each button adds a new message to the inbox for this session (like + notifications that would come from the SDK when content cards are + returned). +
+