diff --git a/src/components/DecisioningEngine/createDecisionProvider.js b/src/components/DecisioningEngine/createDecisionProvider.js index 73e618a2f..245beef50 100644 --- a/src/components/DecisioningEngine/createDecisionProvider.js +++ b/src/components/DecisioningEngine/createDecisionProvider.js @@ -35,10 +35,23 @@ export default ({ eventRegistry }) => { } }; - const evaluate = (context = {}) => - Object.values(payloadsBasedOnActivityId) + const evaluate = (context = {}) => { + const sortedPayloadsBasedOnActivityId = Object.values( + payloadsBasedOnActivityId, + ).sort(({ rank: rankA }, { rank: rankB }) => { + if (rankA < rankB) { + return -1; + } + if (rankA > rankB) { + return 1; + } + return 0; + }); + + return sortedPayloadsBasedOnActivityId .map((payload) => payload.evaluate(context)) .filter((payload) => payload.items.length > 0); + }; const addPayloads = (personalizationPayloads) => { personalizationPayloads.forEach(addPayload); diff --git a/src/components/DecisioningEngine/createEvaluableRulesetPayload.js b/src/components/DecisioningEngine/createEvaluableRulesetPayload.js index bc7adbe6a..23cec655f 100644 --- a/src/components/DecisioningEngine/createEvaluableRulesetPayload.js +++ b/src/components/DecisioningEngine/createEvaluableRulesetPayload.js @@ -95,6 +95,7 @@ export default (payload, eventRegistry, decisionHistory) => { } return { + rank: payload?.scopeDetails?.rank || Infinity, evaluate, isEvaluable: items.length > 0, }; diff --git a/src/components/Personalization/createNotificationHandler.js b/src/components/Personalization/createNotificationHandler.js index 7ab7c1354..2d7f1981f 100644 --- a/src/components/Personalization/createNotificationHandler.js +++ b/src/components/Personalization/createNotificationHandler.js @@ -10,6 +10,7 @@ OF ANY KIND, either express or implied. See the License for the specific languag governing permissions and limitations under the License. */ import { defer } from "../../utils/index.js"; +import { SUPPRESS } from "../../constants/eventType.js"; export default (collect, renderedPropositions) => { return (isRenderDecisions, isSendDisplayEvent, viewName) => { @@ -24,13 +25,29 @@ export default (collect, renderedPropositions) => { return renderedPropositionsDeferred.resolve; } - return (decisionsMeta) => { + return (suppressedPropositions, decisionsMeta) => { if (decisionsMeta.length > 0) { collect({ decisionsMeta, viewName, }); } + + if (suppressedPropositions && suppressedPropositions.length > 0) { + const suppressedMeta = suppressedPropositions.map( + ({ id, scope, scopeDetails }) => ({ + id, + scope, + scopeDetails, + }), + ); + + collect({ + decisionsMeta: suppressedMeta, + eventType: SUPPRESS, + viewName, + }); + } }; }; }; diff --git a/src/components/Personalization/createOnDecisionHandler.js b/src/components/Personalization/createOnDecisionHandler.js index 574f36d37..d410c2e54 100644 --- a/src/components/Personalization/createOnDecisionHandler.js +++ b/src/components/Personalization/createOnDecisionHandler.js @@ -30,13 +30,19 @@ export default ({ const { render, returnedPropositions } = processPropositions( propositionsToExecute, ); + debugger; const handleNotifications = notificationHandler( renderDecisions, sendDisplayEvent, viewName, ); - render().then(handleNotifications); + render().then( + handleNotifications.bind( + null, + returnedPropositions.filter((p) => p.isSuppressedDisplay), + ), + ); return Promise.resolve({ propositions: returnedPropositions, diff --git a/src/components/Personalization/handlers/createProcessInAppMessage.js b/src/components/Personalization/handlers/createProcessInAppMessage.js index 38d4f886a..c65eba67b 100644 --- a/src/components/Personalization/handlers/createProcessInAppMessage.js +++ b/src/components/Personalization/handlers/createProcessInAppMessage.js @@ -47,7 +47,7 @@ const isValidInAppMessage = (data, logger) => { }; export default ({ modules, logger }) => { - return (item) => { + return (item, firstItemInBatch) => { const data = item.getData(); const meta = { ...item.getProposition().getNotification() }; @@ -73,14 +73,16 @@ export default ({ modules, logger }) => { } return { - render: () => { - return modules[type]({ - ...data, - meta, - }); - }, - setRenderAttempted: true, - includeInNotification: true, + render: firstItemInBatch + ? () => + modules[type]({ + ...data, + meta, + }) + : null, + setRenderAttempted: firstItemInBatch, + setSuppressedDisplay: !firstItemInBatch, + includeInNotification: firstItemInBatch, }; }; }; diff --git a/src/components/Personalization/handlers/createProcessPropositions.js b/src/components/Personalization/handlers/createProcessPropositions.js index 6c47136a2..e951fe266 100644 --- a/src/components/Personalization/handlers/createProcessPropositions.js +++ b/src/components/Personalization/handlers/createProcessPropositions.js @@ -50,12 +50,12 @@ export default ({ schemaProcessors, logger }) => { return meta; }); - const processItem = (item) => { + const processItem = (item, firstItemInBatch) => { const processor = schemaProcessors[item.getSchema()]; if (!processor) { return {}; } - return processor(item); + return processor(item, firstItemInBatch); }; const processItems = ({ @@ -64,6 +64,7 @@ export default ({ schemaProcessors, logger }) => { returnedDecisions: existingReturnedDecisions, items, proposition, + firstItemInBatch = false, }) => { let renderers = [...existingRenderers]; let returnedPropositions = [...existingReturnedPropositions]; @@ -74,6 +75,7 @@ export default ({ schemaProcessors, logger }) => { let atLeastOneWithNotification = false; let render; let setRenderAttempted; + let setSuppressedDisplay; let includeInNotification; let onlyRenderThis = false; let i = 0; @@ -81,8 +83,14 @@ export default ({ schemaProcessors, logger }) => { while (items.length > i) { item = items[i]; - ({ render, setRenderAttempted, includeInNotification, onlyRenderThis } = - processItem(item)); + ({ + render, + setRenderAttempted, + setSuppressedDisplay, + includeInNotification, + onlyRenderThis, + } = processItem(item, firstItemInBatch)); + if (onlyRenderThis) { returnedPropositions = []; returnedDecisions = []; @@ -98,6 +106,7 @@ export default ({ schemaProcessors, logger }) => { atLeastOneWithNotification = includeInNotification; break; } + if (render) { itemRenderers.push(wrapRenderWithLogging(render, item)); } @@ -125,6 +134,7 @@ export default ({ schemaProcessors, logger }) => { returnedDecisions, renderedItems, true, + setSuppressedDisplay, ); } if (nonRenderedItems.length > 0) { @@ -133,9 +143,11 @@ export default ({ schemaProcessors, logger }) => { returnedDecisions, nonRenderedItems, false, + setSuppressedDisplay, ); } + debugger; return { renderers, returnedPropositions, @@ -163,6 +175,7 @@ export default ({ schemaProcessors, logger }) => { returnedDecisions, items, proposition, + firstItemInBatch: i === 0, })); if (onlyRenderThis) { break; @@ -194,6 +207,7 @@ export default ({ schemaProcessors, logger }) => { false, ); }); + const render = () => { return Promise.all(renderers.map((renderer) => renderer())).then( (metas) => { diff --git a/src/components/Personalization/handlers/injectCreateProposition.js b/src/components/Personalization/handlers/injectCreateProposition.js index fdc2b85f5..74b66e023 100644 --- a/src/components/Personalization/handlers/injectCreateProposition.js +++ b/src/components/Personalization/handlers/injectCreateProposition.js @@ -90,12 +90,14 @@ export default ({ preprocess, isPageWideSurface }) => { decisions, includedItems, renderAttempted, + isSuppressedDisplay = false, ) { if (visibleInReturnedItems) { propositions.push({ ...payload, items: includedItems.map((i) => i.getOriginalItem()), renderAttempted, + isSuppressedDisplay, }); if (!renderAttempted) { decisions.push({ diff --git a/src/constants/eventType.js b/src/constants/eventType.js index e379a5198..1299715a3 100644 --- a/src/constants/eventType.js +++ b/src/constants/eventType.js @@ -14,4 +14,5 @@ export const DISPLAY = "decisioning.propositionDisplay"; export const INTERACT = "decisioning.propositionInteract"; export const TRIGGER = "decisioning.propositionTrigger"; export const DISMISS = "decisioning.propositionDismiss"; +export const SUPPRESS = "decisioning.propositionSuppressDisplay"; export const EVENT_TYPE_TRUE = 1; diff --git a/src/constants/propositionEventType.js b/src/constants/propositionEventType.js index 3b2358308..ca40fbd3f 100644 --- a/src/constants/propositionEventType.js +++ b/src/constants/propositionEventType.js @@ -10,13 +10,14 @@ OF ANY KIND, either express or implied. See the License for the specific languag governing permissions and limitations under the License. */ -import { DISPLAY, INTERACT, TRIGGER, DISMISS } from "./eventType.js"; +import { DISPLAY, INTERACT, TRIGGER, DISMISS, SUPPRESS } from "./eventType.js"; export const PropositionEventType = { DISPLAY: "display", INTERACT: "interact", TRIGGER: "trigger", DISMISS: "dismiss", + SUPPRESS: "suppressDisplay", }; const eventTypeToPropositionEventTypeMapping = { @@ -24,12 +25,15 @@ const eventTypeToPropositionEventTypeMapping = { [INTERACT]: PropositionEventType.INTERACT, [TRIGGER]: PropositionEventType.TRIGGER, [DISMISS]: PropositionEventType.DISMISS, + [SUPPRESS]: PropositionEventType.SUPPRESS, }; + const propositionEventTypeToEventTypeMapping = { [PropositionEventType.DISPLAY]: DISPLAY, [PropositionEventType.INTERACT]: INTERACT, [PropositionEventType.TRIGGER]: TRIGGER, [PropositionEventType.DISMISS]: DISMISS, + [PropositionEventType.SUPPRESS]: SUPPRESS, }; export const getPropositionEventType = (eventType) =>