Skip to content

Commit 30ffaaf

Browse files
namArora3112Naman Arora
andauthored
PropositionItem class added along with unified track functionality (#507)
* proposition item classes, track funcitonality etc * proposition item uuid added * json proposition item removed * removed unused guide * added htmlProposition , jsonPropositon item class * removed unused apis of content card * generatePropositionInteractionXdm removed * ios implementation of track functionality * uuid vs proposition map added * MessagingProposition class fixes * get proposition for surfaces android fixes * ios get proposition for surface fixes * getproposition for surface updates * MessagingView commented code removed * removed proposition cache with parent * clear cache in update proposition * message util clean up * proposition Item tracking usage refactored * activityID extraction function reusable * white space fixes * added read me for track api usage * removed unnecessary checks before calling track api for android native * refactored extra null checks before calling track api at ios native side * Addeed ios and android logs for null cases * added comments and logs for android native code * marked the trackContentCardInteraction and trackContentCardDisplay as deprecated * added tests for propositionItem.track * read me updated for proposition Item track usage --------- Co-authored-by: Naman Arora <[email protected]>
1 parent 655853f commit 30ffaaf

File tree

17 files changed

+685
-54
lines changed

17 files changed

+685
-54
lines changed

apps/AEPSampleAppNewArchEnabled/app/MessagingView.tsx

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,24 @@ governing permissions and limitations under the License.
1313
import React from 'react';
1414
import {Button, Text, View, ScrollView} from 'react-native';
1515
import {MobileCore} from '@adobe/react-native-aepcore';
16-
import {Messaging, PersonalizationSchema} from '@adobe/react-native-aepmessaging'
16+
import {
17+
Messaging,
18+
PersonalizationSchema,
19+
MessagingEdgeEventType,
20+
PropositionItem,
21+
Message,
22+
ContentCard,
23+
HTMLProposition,
24+
JSONPropositionItem
25+
} from '@adobe/react-native-aepmessaging'
26+
import { MessagingProposition } from '@adobe/react-native-aepmessaging';
1727
import styles from '../styles/styles';
1828
import { useRouter } from 'expo-router';
1929

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

33+
2334
const messagingExtensionVersion = async () => {
2435
const version = await Messaging.extensionVersion();
2536
console.log(`AdobeExperienceSDK: Messaging version: ${version}`);
@@ -40,12 +51,10 @@ const setMessagingDelegate = () => {
4051
});
4152
console.log('messaging delegate set');
4253
};
43-
4454
const getPropositionsForSurfaces = async () => {
4555
const messages = await Messaging.getPropositionsForSurfaces(SURFACES);
4656
console.log(JSON.stringify(messages));
4757
};
48-
4958
const trackAction = async () => {
5059
MobileCore.trackAction('tuesday', {full: true});
5160
};
@@ -75,7 +84,8 @@ const trackContentCardInteraction = async () => {
7584
for (const proposition of propositions) {
7685
for (const propositionItem of proposition.items) {
7786
if (propositionItem.schema === PersonalizationSchema.CONTENT_CARD) {
78-
Messaging.trackContentCardInteraction(proposition, propositionItem);
87+
// Cast to ContentCard for the legacy tracking method
88+
Messaging.trackContentCardInteraction(proposition, propositionItem as any);
7989
console.log('trackContentCardInteraction', proposition, propositionItem);
8090
}
8191
}
@@ -93,14 +103,35 @@ const trackContentCardDisplay = async () => {
93103
for (const proposition of propositions) {
94104
for (const propositionItem of proposition.items) {
95105
if (propositionItem.schema === PersonalizationSchema.CONTENT_CARD) {
96-
Messaging.trackContentCardDisplay(proposition, propositionItem);
106+
// Cast to ContentCard for the legacy tracking method
107+
Messaging.trackContentCardDisplay(proposition, propositionItem as any);
97108
console.log('trackContentCardDisplay', proposition, propositionItem);
98109
}
99110
}
100111
}
101112
}
102113
}
103114

115+
116+
// Method demonstrating unified tracking using PropositionItem methods
117+
const unifiedTrackingExample = async () => {
118+
const messages = await Messaging.getPropositionsForSurfaces(SURFACES);
119+
for (const surface of SURFACES) {
120+
const propositions = messages[surface] || [];
121+
122+
for (const proposition of propositions) {
123+
const propositionWrapper = new MessagingProposition(proposition);
124+
if (propositionWrapper.items.length > 0) {
125+
const propositionItem = propositionWrapper.items[0];
126+
propositionItem.track(MessagingEdgeEventType.DISPLAY);
127+
propositionItem.track('content_card_clicked', MessagingEdgeEventType.INTERACT, null);
128+
}
129+
}
130+
}
131+
}
132+
133+
134+
104135
function MessagingView() {
105136
const router = useRouter();
106137

@@ -125,6 +156,7 @@ function MessagingView() {
125156
<Button title="trackAction()" onPress={trackAction} />
126157
<Button title="trackPropositionInteraction()" onPress={trackContentCardInteraction} />
127158
<Button title="trackContentCardDisplay()" onPress={trackContentCardDisplay} />
159+
<Button title="Unified Tracking Example" onPress={unifiedTrackingExample} />
128160
</ScrollView>
129161
</View>
130162
);

packages/messaging/README.md

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,53 @@ for (let item in proposition.items) {
201201
}
202202
```
203203

204+
205+
### PropositionItem.track
206+
207+
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.
208+
209+
#### Using PropositionItem.track (recommended)
210+
211+
**Syntax**
212+
213+
```javascript
214+
// Track display event
215+
propositionItem.track(MessagingEdgeEventType.DISPLAY);
216+
217+
// Track interaction with custom data + event + optional tokens
218+
propositionItem.track(
219+
interaction /* string | null */,
220+
MessagingEdgeEventType.INTERACT /* enum value */,
221+
[/* tokens */] /* string[] | null */
222+
);
223+
```
224+
225+
When using `getPropositionsForSurfaces`, the returned objects can be wrapped with `MessagingProposition` to get typed items and convenient tracking via `PropositionItem.track(...)`.
226+
227+
```javascript
228+
import { Messaging, MessagingProposition, MessagingEdgeEventType } from '@adobe/react-native-aepmessaging';
229+
230+
const SURFACES = ['mobileapp://my-surface'];
231+
const messages = await Messaging.getPropositionsForSurfaces(SURFACES);
232+
233+
for (const surface of SURFACES) {
234+
const propositions = messages[surface] || [];
235+
236+
for (const proposition of propositions) {
237+
const msgProp = new MessagingProposition(proposition);
238+
239+
if (msgProp.items.length > 0) {
240+
const propositionItem = msgProp.items[0];
241+
242+
// Track interaction with custom data
243+
propositionItem.track('content_card_clicked', MessagingEdgeEventType.INTERACT, null);
244+
// Track with tokens for sub-item tracking
245+
propositionItem.track('button_click', MessagingEdgeEventType.INTERACT, ['token-1', 'token-2']);
246+
}
247+
}
248+
}
249+
```
250+
204251
### getLatestMessage
205252

206253
Retrieves the most recently displayed message object
@@ -440,6 +487,8 @@ function otherWorkflowFinished() {
440487
441488
### trackContentCardDisplay
442489
490+
Deprecated: Use `PropositionItem.track(...)` instead. This API will be removed in a future release.
491+
443492
Tracks a Display interaction with the given ContentCard
444493
445494
**Syntax**
@@ -449,6 +498,8 @@ Messaging.trackContentCardDisplay(proposition, contentCard);
449498
450499
### trackContentCardInteraction
451500
501+
Deprecated: Use `PropositionItem.track(...)` instead. This API will be removed in a future release.
502+
452503
Tracks a Click interaction with the given ContentCard
453504
454505
**Syntax**
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
Copyright 2025 Adobe. All rights reserved.
3+
This file is licensed to you under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License. You may obtain a copy
5+
of the License at http://www.apache.org/licenses/LICENSE-2.0
6+
7+
Unless required by applicable law or agreed to in writing, software distributed under
8+
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9+
OF ANY KIND, either express or implied. See the License for the specific language
10+
governing permissions and limitations under the License.
11+
*/
12+
13+
import { NativeModules } from 'react-native';
14+
import { MessagingEdgeEventType, PropositionItem, PropositionItemData, PersonalizationSchema } from '../src';
15+
16+
describe('PropositionItem', () => {
17+
const uuid = 'activity-uuid-123';
18+
const id = 'item-abc';
19+
const activityID = uuid; // mirrors native mapping
20+
21+
const baseData: PropositionItemData = {
22+
id,
23+
uuid,
24+
activityID,
25+
schema: PersonalizationSchema.CONTENT_CARD,
26+
data: { foo: 'bar' },
27+
};
28+
29+
beforeEach(() => {
30+
jest.clearAllMocks();
31+
});
32+
33+
it('track(eventType) calls native with null interaction and tokens', () => {
34+
const item = new PropositionItem(baseData);
35+
item.track(MessagingEdgeEventType.DISPLAY);
36+
37+
expect(NativeModules.AEPMessaging.trackPropositionItem).toHaveBeenCalledWith(
38+
activityID,
39+
null,
40+
MessagingEdgeEventType.DISPLAY,
41+
null
42+
);
43+
});
44+
45+
it('track(interaction, eventType, tokens=null) forwards interaction', () => {
46+
const item = new PropositionItem(baseData);
47+
item.track('click', MessagingEdgeEventType.INTERACT, null);
48+
49+
expect(NativeModules.AEPMessaging.trackPropositionItem).toHaveBeenCalledWith(
50+
activityID,
51+
'click',
52+
MessagingEdgeEventType.INTERACT,
53+
null
54+
);
55+
});
56+
57+
it('track(interaction, eventType, tokens[]) forwards tokens array', () => {
58+
const item = new PropositionItem(baseData);
59+
const tokens = ['t1', 't2'];
60+
item.track('click', MessagingEdgeEventType.INTERACT, tokens);
61+
62+
expect(NativeModules.AEPMessaging.trackPropositionItem).toHaveBeenCalledWith(
63+
activityID,
64+
'click',
65+
MessagingEdgeEventType.INTERACT,
66+
tokens
67+
);
68+
});
69+
70+
it('track(null, eventType, tokens[]) supports null interaction with tokens', () => {
71+
const item = new PropositionItem(baseData);
72+
const tokens = ['a'];
73+
item.track(null, MessagingEdgeEventType.DISPLAY, tokens);
74+
75+
expect(NativeModules.AEPMessaging.trackPropositionItem).toHaveBeenCalledWith(
76+
activityID,
77+
null,
78+
MessagingEdgeEventType.DISPLAY,
79+
tokens
80+
);
81+
});
82+
});
83+
84+

0 commit comments

Comments
 (0)