Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
02a791a
proposition item classes, track funcitonality etc
Aug 7, 2025
af23662
proposition item uuid added
Aug 18, 2025
c8ccc75
json proposition item removed
Aug 18, 2025
a17849a
removed unused guide
Aug 19, 2025
3e36a29
added htmlProposition , jsonPropositon item class
Aug 19, 2025
8e5f825
removed unused apis of content card
Aug 19, 2025
1ef7a89
generatePropositionInteractionXdm removed
Aug 20, 2025
ef8977d
ios implementation of track functionality
Aug 20, 2025
fc21588
uuid vs proposition map added
Aug 20, 2025
cf02267
MessagingProposition class fixes
Aug 25, 2025
911271c
get proposition for surfaces android fixes
Aug 25, 2025
c116f69
ios get proposition for surface fixes
Aug 25, 2025
0fe8633
getproposition for surface updates
Aug 25, 2025
77a0b2d
MessagingView commented code removed
Aug 25, 2025
61c6c4d
removed proposition cache with parent
Aug 25, 2025
93c3d13
clear cache in update proposition
Aug 25, 2025
d70c369
message util clean up
Aug 25, 2025
13a2c87
proposition Item tracking usage refactored
Aug 25, 2025
1a78103
activityID extraction function reusable
Aug 26, 2025
b2c6bd0
white space fixes
Aug 26, 2025
d2f7f02
added read me for track api usage
Aug 26, 2025
2739a9e
removed unnecessary checks before calling track api for android native
Aug 27, 2025
b4ad0c2
refactored extra null checks before calling track api at ios native side
Aug 27, 2025
8a6c41e
Addeed ios and android logs for null cases
Aug 27, 2025
732db7d
added comments and logs for android native code
Aug 31, 2025
dd28137
marked the trackContentCardInteraction and trackContentCardDisplay as…
Aug 31, 2025
91d3dbc
added tests for propositionItem.track
Aug 31, 2025
4c4e2ec
read me updated for proposition Item track usage
Aug 31, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 37 additions & 5 deletions apps/AEPSampleAppNewArchEnabled/app/MessagingView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,24 @@ governing permissions and limitations under the License.
import React from 'react';
import {Button, Text, View, ScrollView} from 'react-native';
import {MobileCore} from '@adobe/react-native-aepcore';
import {Messaging, PersonalizationSchema} from '@adobe/react-native-aepmessaging'
import {
Messaging,
PersonalizationSchema,
MessagingEdgeEventType,
PropositionItem,
Message,
ContentCard,
HTMLProposition,
JSONPropositionItem
} from '@adobe/react-native-aepmessaging'
import { MessagingProposition } from '@adobe/react-native-aepmessaging';
import styles from '../styles/styles';
import { useRouter } from 'expo-router';

const SURFACES = ['android-cbe-preview', 'cbe/json', 'android-cc'];
const SURFACES_WITH_CONTENT_CARDS = ['android-cc'];


const messagingExtensionVersion = async () => {
const version = await Messaging.extensionVersion();
console.log(`AdobeExperienceSDK: Messaging version: ${version}`);
Expand All @@ -40,12 +51,10 @@ const setMessagingDelegate = () => {
});
console.log('messaging delegate set');
};

const getPropositionsForSurfaces = async () => {
const messages = await Messaging.getPropositionsForSurfaces(SURFACES);
console.log(JSON.stringify(messages));
};

const trackAction = async () => {
MobileCore.trackAction('tuesday', {full: true});
};
Expand Down Expand Up @@ -75,7 +84,8 @@ const trackContentCardInteraction = async () => {
for (const proposition of propositions) {
for (const propositionItem of proposition.items) {
if (propositionItem.schema === PersonalizationSchema.CONTENT_CARD) {
Messaging.trackContentCardInteraction(proposition, propositionItem);
// Cast to ContentCard for the legacy tracking method
Messaging.trackContentCardInteraction(proposition, propositionItem as any);
console.log('trackContentCardInteraction', proposition, propositionItem);
}
}
Expand All @@ -93,14 +103,35 @@ const trackContentCardDisplay = async () => {
for (const proposition of propositions) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you plan to deprecate this method trackContentCardDisplay
let's just mark it and the we might also have to update the documentation

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes have added in the typescript and also in documentation too

for (const propositionItem of proposition.items) {
if (propositionItem.schema === PersonalizationSchema.CONTENT_CARD) {
Messaging.trackContentCardDisplay(proposition, propositionItem);
// Cast to ContentCard for the legacy tracking method
Messaging.trackContentCardDisplay(proposition, propositionItem as any);
console.log('trackContentCardDisplay', proposition, propositionItem);
}
}
}
}
}


// Method demonstrating unified tracking using PropositionItem methods
const unifiedTrackingExample = async () => {
const messages = await Messaging.getPropositionsForSurfaces(SURFACES);
for (const surface of SURFACES) {
const propositions = messages[surface] || [];

for (const proposition of propositions) {
const propositionWrapper = new MessagingProposition(proposition);
if (propositionWrapper.items.length > 0) {
const propositionItem = propositionWrapper.items[0];
propositionItem.track(MessagingEdgeEventType.DISPLAY);
propositionItem.track('content_card_clicked', MessagingEdgeEventType.INTERACT, null);
}
}
}
}



function MessagingView() {
const router = useRouter();

Expand All @@ -125,6 +156,7 @@ function MessagingView() {
<Button title="trackAction()" onPress={trackAction} />
<Button title="trackPropositionInteraction()" onPress={trackContentCardInteraction} />
<Button title="trackContentCardDisplay()" onPress={trackContentCardDisplay} />
<Button title="Unified Tracking Example" onPress={unifiedTrackingExample} />
</ScrollView>
</View>
);
Expand Down
51 changes: 51 additions & 0 deletions packages/messaging/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,53 @@ for (let item in proposition.items) {
}
```


### PropositionItem.track

A unified tracking API is available for any proposition item (Content Cards, HTML, JSON, code-based items). You can use the same track() method regardless of content type, making your code more consistent and maintainable.

#### Using PropositionItem.track (recommended)

**Syntax**

```javascript
// Track display event
propositionItem.track(MessagingEdgeEventType.DISPLAY);

// Track interaction with custom data + event + optional tokens
propositionItem.track(
interaction /* string | null */,
MessagingEdgeEventType.INTERACT /* enum value */,
[/* tokens */] /* string[] | null */
);
```

When using `getPropositionsForSurfaces`, the returned objects can be wrapped with `MessagingProposition` to get typed items and convenient tracking via `PropositionItem.track(...)`.

```javascript
import { Messaging, MessagingProposition, MessagingEdgeEventType } from '@adobe/react-native-aepmessaging';

const SURFACES = ['mobileapp://my-surface'];
const messages = await Messaging.getPropositionsForSurfaces(SURFACES);

for (const surface of SURFACES) {
const propositions = messages[surface] || [];

for (const proposition of propositions) {
const msgProp = new MessagingProposition(proposition);

if (msgProp.items.length > 0) {
const propositionItem = msgProp.items[0];

// Track interaction with custom data
propositionItem.track('content_card_clicked', MessagingEdgeEventType.INTERACT, null);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: there is an extra space before
// Track ....
"propositionItem.track('content_card_clicked', MessagingEdgeEventType.INTERACT, null);"

They are not align with the next // Track ....

// Track with tokens for sub-item tracking
propositionItem.track('button_click', MessagingEdgeEventType.INTERACT, ['token-1', 'token-2']);
}
}
}
```

### getLatestMessage

Retrieves the most recently displayed message object
Expand Down Expand Up @@ -440,6 +487,8 @@ function otherWorkflowFinished() {

### trackContentCardDisplay

Deprecated: Use `PropositionItem.track(...)` instead. This API will be removed in a future release.

Tracks a Display interaction with the given ContentCard

**Syntax**
Expand All @@ -449,6 +498,8 @@ Messaging.trackContentCardDisplay(proposition, contentCard);

### trackContentCardInteraction

Deprecated: Use `PropositionItem.track(...)` instead. This API will be removed in a future release.

Tracks a Click interaction with the given ContentCard

**Syntax**
Expand Down
84 changes: 84 additions & 0 deletions packages/messaging/__tests__/PropositionItemTests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
Copyright 2025 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License.
*/

import { NativeModules } from 'react-native';
import { MessagingEdgeEventType, PropositionItem, PropositionItemData, PersonalizationSchema } from '../src';

describe('PropositionItem', () => {
const uuid = 'activity-uuid-123';
const id = 'item-abc';
const activityID = uuid; // mirrors native mapping

const baseData: PropositionItemData = {
id,
uuid,
activityID,
schema: PersonalizationSchema.CONTENT_CARD,
data: { foo: 'bar' },
};

beforeEach(() => {
jest.clearAllMocks();
});

it('track(eventType) calls native with null interaction and tokens', () => {
const item = new PropositionItem(baseData);
item.track(MessagingEdgeEventType.DISPLAY);

expect(NativeModules.AEPMessaging.trackPropositionItem).toHaveBeenCalledWith(
activityID,
null,
MessagingEdgeEventType.DISPLAY,
null
);
});

it('track(interaction, eventType, tokens=null) forwards interaction', () => {
const item = new PropositionItem(baseData);
item.track('click', MessagingEdgeEventType.INTERACT, null);

expect(NativeModules.AEPMessaging.trackPropositionItem).toHaveBeenCalledWith(
activityID,
'click',
MessagingEdgeEventType.INTERACT,
null
);
});

it('track(interaction, eventType, tokens[]) forwards tokens array', () => {
const item = new PropositionItem(baseData);
const tokens = ['t1', 't2'];
item.track('click', MessagingEdgeEventType.INTERACT, tokens);

expect(NativeModules.AEPMessaging.trackPropositionItem).toHaveBeenCalledWith(
activityID,
'click',
MessagingEdgeEventType.INTERACT,
tokens
);
});

it('track(null, eventType, tokens[]) supports null interaction with tokens', () => {
const item = new PropositionItem(baseData);
const tokens = ['a'];
item.track(null, MessagingEdgeEventType.DISPLAY, tokens);

expect(NativeModules.AEPMessaging.trackPropositionItem).toHaveBeenCalledWith(
activityID,
null,
MessagingEdgeEventType.DISPLAY,
tokens
);
});
});


Loading