Skip to content

Commit 1986caa

Browse files
committed
feat: implement getEmbeddedMessages method and add example on embedded
1 parent 760a9e3 commit 1986caa

File tree

16 files changed

+255
-25
lines changed

16 files changed

+255
-25
lines changed

android/src/main/java/com/iterable/reactnative/RNIterableAPIModuleImpl.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -683,6 +683,41 @@ public void getEmbeddedPlacementIds(Promise promise) {
683683
}
684684
}
685685

686+
public void getEmbeddedMessages(@Nullable ReadableArray placementIds, Promise promise) {
687+
IterableLogger.d(TAG, "getEmbeddedMessages for placements: " + placementIds);
688+
689+
try {
690+
List<IterableEmbeddedMessage> allMessages = new ArrayList<>();
691+
692+
if (placementIds == null || placementIds.size() == 0) {
693+
// If no placement IDs provided, we need to get messages for all possible placements
694+
// Since the Android SDK requires a placement ID, we'll use 0 as a default
695+
// This might need to be adjusted based on the actual SDK behavior
696+
List<IterableEmbeddedMessage> messages = IterableApi.getInstance().getEmbeddedManager().getMessages(0L);
697+
if (messages != null) {
698+
allMessages.addAll(messages);
699+
}
700+
} else {
701+
// Convert ReadableArray to individual placement IDs and get messages for each
702+
for (int i = 0; i < placementIds.size(); i++) {
703+
long placementId = placementIds.getInt(i);
704+
List<IterableEmbeddedMessage> messages = IterableApi.getInstance().getEmbeddedManager().getMessages(placementId);
705+
if (messages != null) {
706+
allMessages.addAll(messages);
707+
}
708+
}
709+
}
710+
711+
JSONArray embeddedMessageJsonArray = Serialization.serializeEmbeddedMessages(allMessages);
712+
IterableLogger.d(TAG, "Messages for placements: " + embeddedMessageJsonArray);
713+
714+
promise.resolve(Serialization.convertJsonToArray(embeddedMessageJsonArray));
715+
} catch (JSONException e) {
716+
IterableLogger.e(TAG, e.getLocalizedMessage());
717+
promise.reject("", "Failed to fetch messages with error " + e.getLocalizedMessage());
718+
}
719+
}
720+
686721
// ---------------------------------------------------------------------------------------
687722
// endregion
688723
}

android/src/main/java/com/iterable/reactnative/Serialization.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,17 @@ static JSONArray serializeInAppMessages(List<IterableInAppMessage> inAppMessages
138138
return inAppMessagesJson;
139139
}
140140

141+
static JSONArray serializeEmbeddedMessages(List<IterableEmbeddedMessage> embeddedMessages) {
142+
JSONArray embeddedMessagesJson = new JSONArray();
143+
if (embeddedMessages != null) {
144+
for (IterableEmbeddedMessage message : embeddedMessages) {
145+
JSONObject messageJson = IterableEmbeddedMessage.Companion.toJSONObject(message);
146+
embeddedMessagesJson.put(messageJson);
147+
}
148+
}
149+
return embeddedMessagesJson;
150+
}
151+
141152
static IterableConfig.Builder getConfigFromReadableMap(ReadableMap iterableContextMap) {
142153
try {
143154
JSONObject iterableContextJSON = convertMapToJson(iterableContextMap);

android/src/newarch/java/com/RNIterableAPIModule.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,11 @@ public void getEmbeddedPlacementIds(Promise promise) {
244244
moduleImpl.getEmbeddedPlacementIds(promise);
245245
}
246246

247+
@Override
248+
public void getEmbeddedMessages(@Nullable ReadableArray placementIds, Promise promise) {
249+
moduleImpl.getEmbeddedMessages(placementIds, promise);
250+
}
251+
247252
public void sendEvent(@NonNull String eventName, @Nullable Object eventData) {
248253
moduleImpl.sendEvent(eventName, eventData);
249254
}

android/src/oldarch/java/com/RNIterableAPIModule.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,11 @@ public void getEmbeddedPlacementIds(Promise promise) {
248248
moduleImpl.getEmbeddedPlacementIds(promise);
249249
}
250250

251+
@ReactMethod
252+
public void getEmbeddedMessages(@Nullable ReadableArray placementIds, Promise promise) {
253+
moduleImpl.getEmbeddedMessages(placementIds, promise);
254+
}
255+
251256
public void sendEvent(@NonNull String eventName, @Nullable Object eventData) {
252257
moduleImpl.sendEvent(eventName, eventData);
253258
}

example/src/components/Embedded/Embedded.tsx

Lines changed: 57 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,27 @@
11
import { Text, TouchableOpacity, View } from 'react-native';
22
import { useCallback, useState } from 'react';
3-
import { Iterable } from '@iterable/react-native-sdk';
3+
import {
4+
Iterable,
5+
type IterableEmbeddedMessage,
6+
} from '@iterable/react-native-sdk';
47

58
import styles from './Embedded.styles';
69

710
export const Embedded = () => {
811
const [placementIds, setPlacementIds] = useState<number[]>([]);
12+
const [embeddedMessages, setEmbeddedMessages] = useState<
13+
IterableEmbeddedMessage[]
14+
>([]);
915

1016
const syncEmbeddedMessages = useCallback(() => {
1117
Iterable.embeddedManager.syncMessages();
1218
}, []);
1319

1420
const getPlacementIds = useCallback(() => {
15-
Iterable.embeddedManager.getPlacementIds().then((ids: unknown) => {
21+
return Iterable.embeddedManager.getPlacementIds().then((ids: unknown) => {
1622
console.log(ids);
1723
setPlacementIds(ids as number[]);
24+
return ids;
1825
});
1926
}, []);
2027

@@ -32,31 +39,57 @@ export const Embedded = () => {
3239
Iterable.embeddedManager.endSession();
3340
}, []);
3441

42+
const getEmbeddedMessages = useCallback(() => {
43+
getPlacementIds()
44+
.then((ids: number[]) => Iterable.embeddedManager.getMessages(ids))
45+
.then((messages: IterableEmbeddedMessage[]) => {
46+
setEmbeddedMessages(messages);
47+
console.log(messages);
48+
});
49+
}, [getPlacementIds]);
50+
3551
return (
3652
<View style={styles.container}>
3753
<Text style={styles.text}>EMBEDDED</Text>
38-
<Text style={styles.text}>
39-
Does embedded class exist? {Iterable.embeddedManager ? 'Yes' : 'No'}
40-
</Text>
41-
<Text style={styles.text}>
42-
Is embedded manager enabled?
43-
{Iterable.embeddedManager.isEnabled ? 'Yes' : 'No'}
44-
</Text>
45-
<Text style={styles.text}>
46-
Placement ids: [{placementIds.join(', ')}]
47-
</Text>
48-
<TouchableOpacity style={styles.button} onPress={syncEmbeddedMessages}>
49-
<Text style={styles.buttonText}>Sync embedded messages</Text>
50-
</TouchableOpacity>
51-
<TouchableOpacity style={styles.button} onPress={getPlacementIds}>
52-
<Text style={styles.buttonText}>Get placement ids</Text>
53-
</TouchableOpacity>
54-
<TouchableOpacity style={styles.button} onPress={startEmbeddedSession}>
55-
<Text style={styles.buttonText}>Start embedded session</Text>
56-
</TouchableOpacity>
57-
<TouchableOpacity style={styles.button} onPress={endEmbeddedSession}>
58-
<Text style={styles.buttonText}>End embedded session</Text>
59-
</TouchableOpacity>
54+
<View style={styles.utilitySection}>
55+
<Text style={styles.text}>
56+
Does embedded class exist? {Iterable.embeddedManager ? 'Yes' : 'No'}
57+
</Text>
58+
<Text style={styles.text}>
59+
Is embedded manager enabled?
60+
{Iterable.embeddedManager.isEnabled ? 'Yes' : 'No'}
61+
</Text>
62+
<Text style={styles.text}>
63+
Placement ids: [{placementIds.join(', ')}]
64+
</Text>
65+
<TouchableOpacity style={styles.button} onPress={syncEmbeddedMessages}>
66+
<Text style={styles.buttonText}>Sync embedded messages</Text>
67+
</TouchableOpacity>
68+
<TouchableOpacity style={styles.button} onPress={getPlacementIds}>
69+
<Text style={styles.buttonText}>Get placement ids</Text>
70+
</TouchableOpacity>
71+
<TouchableOpacity style={styles.button} onPress={startEmbeddedSession}>
72+
<Text style={styles.buttonText}>Start embedded session</Text>
73+
</TouchableOpacity>
74+
<TouchableOpacity style={styles.button} onPress={endEmbeddedSession}>
75+
<Text style={styles.buttonText}>End embedded session</Text>
76+
</TouchableOpacity>
77+
<TouchableOpacity style={styles.button} onPress={getEmbeddedMessages}>
78+
<Text style={styles.buttonText}>Get embedded messages</Text>
79+
</TouchableOpacity>
80+
</View>
81+
<View style={styles.hr} />
82+
<View style={styles.embeddedSection}>
83+
{embeddedMessages.map((message) => (
84+
<View key={message.metadata.messageId}>
85+
<Text>Embedded message</Text>
86+
<Text>metadata.messageId: {message.metadata.messageId}</Text>
87+
<Text>metadata.placementId: {message.metadata.placementId}</Text>
88+
<Text>elements.title: {message.elements?.title}</Text>
89+
<Text>elements.body: {message.elements?.body}</Text>
90+
</View>
91+
))}
92+
</View>
6093
</View>
6194
);
6295
};

src/api/NativeRNIterableAPI.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,33 @@
11
import type { TurboModule } from 'react-native';
22
import { TurboModuleRegistry } from 'react-native';
33

4+
// NOTE: No types can be imported because of the way new arch works, so we have
5+
// to re-define the types here.
6+
interface EmbeddedMessage {
7+
metadata: {
8+
messageId: string;
9+
placementId: number;
10+
campaignId?: number | null;
11+
isProof?: boolean;
12+
};
13+
elements: {
14+
buttons?:
15+
| {
16+
id: string;
17+
title?: string | null;
18+
action: { type: string; data?: string } | null;
19+
}[]
20+
| null;
21+
body?: string | null;
22+
mediaUrl?: string | null;
23+
mediaUrlCaption?: string | null;
24+
defaultAction?: { type: string; data?: string } | null;
25+
text?: { id: string; text?: string | null; label?: string | null }[] | null;
26+
title?: string | null;
27+
} | null;
28+
payload?: { [key: string]: string | number | boolean | null } | null;
29+
}
30+
431
export interface Spec extends TurboModule {
532
// Initialization
633
initializeWithApiKey(
@@ -123,6 +150,9 @@ export interface Spec extends TurboModule {
123150
startEmbeddedSession(): void;
124151
endEmbeddedSession(): void;
125152
getEmbeddedPlacementIds(): Promise<number[]>;
153+
getEmbeddedMessages(
154+
placementIds: number[] | null
155+
): Promise<EmbeddedMessage[]>;
126156

127157
// Wake app -- android only
128158
wakeApp(): void;

src/core/classes/IterableApi.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { IterableAttributionInfo } from './IterableAttributionInfo';
1212
import type { IterableCommerceItem } from './IterableCommerceItem';
1313
import { IterableConfig } from './IterableConfig';
1414
import { IterableLogger } from './IterableLogger';
15+
import type { IterableEmbeddedMessage } from '../../embedded/types/IterableEmbeddedMessage';
1516

1617
/**
1718
* Contains functions that directly interact with the native layer.
@@ -542,6 +543,18 @@ export class IterableApi {
542543
return RNIterableAPI.getEmbeddedPlacementIds();
543544
}
544545

546+
/**
547+
* Get the embedded messages.
548+
*
549+
* @returns A Promise that resolves to an array of embedded messages.
550+
*/
551+
static getEmbeddedMessages(
552+
placementIds: number[] | null
553+
): Promise<IterableEmbeddedMessage[]> {
554+
IterableLogger.log('getEmbeddedMessages: ', placementIds);
555+
return RNIterableAPI.getEmbeddedMessages(placementIds);
556+
}
557+
545558
// ---- End EMBEDDED ---- //
546559

547560
// ====================================================== //

src/embedded/classes/IterableEmbeddedManager.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { IterableApi } from '../../core/classes/IterableApi';
2+
import type { IterableEmbeddedMessage } from '../types/IterableEmbeddedMessage';
23

34
/**
45
* Manages embedded messages from Iterable.
@@ -52,6 +53,18 @@ export class IterableEmbeddedManager {
5253
return IterableApi.getEmbeddedPlacementIds();
5354
}
5455

56+
/**
57+
* Retrieves a list of embedded messages the user is eligible to see.
58+
*
59+
* @param placementIds - The placement IDs to retrieve messages for.
60+
* @returns A Promise that resolves to an array of embedded messages.
61+
*/
62+
getMessages(
63+
placementIds: number[] | null
64+
): Promise<IterableEmbeddedMessage[]> {
65+
return IterableApi.getEmbeddedMessages(placementIds);
66+
}
67+
5568
/**
5669
* Starts a session.
5770
*

src/embedded/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
export * from './classes';
2+
export * from './types';
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import type { IterableEmbeddedMessageElements } from './IterableEmbeddedMessageElements';
2+
import type { IterableEmbeddedMessageMetadata } from './IterableEmbeddedMessageMetadata';
3+
4+
/**
5+
* An embedded message.
6+
*/
7+
export interface IterableEmbeddedMessage {
8+
/** Identifying information about the campaign. */
9+
metadata: IterableEmbeddedMessageMetadata;
10+
/** What to display, and how to handle interaction. */
11+
elements?: IterableEmbeddedMessageElements | null;
12+
/** Custom JSON data included with the campaign. */
13+
payload?: Record<string, unknown> | null;
14+
}

0 commit comments

Comments
 (0)