Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -719,23 +719,6 @@ public void pauseEmbeddedImpression(String messageId) {
IterableApi.getInstance().getEmbeddedManager().getEmbeddedSessionManager().pauseImpression(messageId);
}

public void getEmbeddedPlacementIds(Promise promise) {
IterableLogger.d(TAG, "getEmbeddedPlacementIds");
try {
List<Long> placementIds = IterableApi.getInstance().getEmbeddedManager().getPlacementIds();
WritableArray writableArray = Arguments.createArray();
if (placementIds != null) {
for (Long placementId : placementIds) {
writableArray.pushDouble(placementId.doubleValue());
}
}
promise.resolve(writableArray);
} catch (Exception e) {
IterableLogger.e(TAG, "Error getting placement IDs: " + e.getLocalizedMessage());
promise.reject("", "Failed to get placement IDs: " + e.getLocalizedMessage());
}
}

public void getEmbeddedMessages(@Nullable ReadableArray placementIds, Promise promise) {
IterableLogger.d(TAG, "getEmbeddedMessages for placements: " + placementIds);

Expand Down
5 changes: 0 additions & 5 deletions android/src/newarch/java/com/RNIterableAPIModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -249,11 +249,6 @@ public void pauseEmbeddedImpression(String messageId) {
moduleImpl.pauseEmbeddedImpression(messageId);
}

@Override
public void getEmbeddedPlacementIds(Promise promise) {
moduleImpl.getEmbeddedPlacementIds(promise);
}

@Override
public void getEmbeddedMessages(@Nullable ReadableArray placementIds, Promise promise) {
moduleImpl.getEmbeddedMessages(placementIds, promise);
Expand Down
5 changes: 0 additions & 5 deletions android/src/oldarch/java/com/RNIterableAPIModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -253,11 +253,6 @@ public void pauseEmbeddedImpression(String messageId) {
moduleImpl.pauseEmbeddedImpression(messageId);
}

@ReactMethod
public void getEmbeddedPlacementIds(Promise promise) {
moduleImpl.getEmbeddedPlacementIds(promise);
}

@ReactMethod
public void getEmbeddedMessages(@Nullable ReadableArray placementIds, Promise promise) {
moduleImpl.getEmbeddedMessages(placementIds, promise);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import com.facebook.react.ReactActivity
import com.facebook.react.ReactActivityDelegate
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled
import com.facebook.react.defaults.DefaultReactActivityDelegate
import com.iterable.iterableapi.IterableApi

class MainActivity : ReactActivity() {

Expand All @@ -27,6 +28,8 @@ class MainActivity : ReactActivity() {
* This being in Kotlin **may** cause issues with react-native-screens
*/
override fun onCreate(savedInstanceState: Bundle?) {
IterableApi.setContext(this)
// Call super.onCreate with null to prevent savedInstanceState restoration issues
super.onCreate(null)
Comment on lines +32 to 33
Copy link

Copilot AI Jan 12, 2026

Choose a reason for hiding this comment

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

Passing null to super.onCreate instead of savedInstanceState prevents the restoration of the activity's saved state. This could affect the app's ability to restore its state after configuration changes (like screen rotation) or when the app is killed and restored by the system. While this is example code, it sets a poor pattern for developers who might copy this implementation. If this is necessary for the Iterable SDK to work correctly, it should be documented in the SDK's integration guide with an explanation of why it's needed and what trade-offs it entails.

Copilot uses AI. Check for mistakes.
}
}
}
34 changes: 32 additions & 2 deletions example/src/components/Embedded/Embedded.styles.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
import { StyleSheet } from 'react-native';
import { button, buttonText, container, hr, link } from '../../constants';
import { button, buttonText, container, hr, link, input, title, subtitle } from '../../constants';
import { neutrals, utilityColors, backgroundColors } from '../../constants/styles/colors';

const styles = StyleSheet.create({
button,
buttonDisabled: {
backgroundColor: neutrals.grey25,
opacity: 0.6,
},
buttonText,
container: { ...container, paddingHorizontal: 0 },
buttonTextDisabled: {
color: neutrals.grey50,
},
container,
embeddedSection: {
display: 'flex',
flexDirection: 'column',
Expand All @@ -21,11 +29,33 @@ const styles = StyleSheet.create({
flexDirection: 'row',
},
hr,
inputContainer: {
marginVertical: 10,
},
link,
subtitle: { ...subtitle, textAlign: 'center' },
text: { textAlign: 'center' },
textInput: input,
title: { ...title, textAlign: 'center' },
utilitySection: {
paddingHorizontal: 16,
},
warningContainer: {
backgroundColor: backgroundColors.backgroundWarningSubtle,
borderLeftColor: utilityColors.warning100,
borderLeftWidth: 4,
borderRadius: 5,
marginBottom: 12,
marginHorizontal: 16,
marginTop: 0,
padding: 12,
},
warningText: {
color: utilityColors.warning100,
fontSize: 14,
fontWeight: '600',
textAlign: 'center',
},
});

export default styles;
92 changes: 62 additions & 30 deletions example/src/components/Embedded/Embedded.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ScrollView, Text, TouchableOpacity, View } from 'react-native';
import { ScrollView, Text, TextInput, TouchableOpacity, View } from 'react-native';
import { useCallback, useState } from 'react';
import {
Iterable,
Expand All @@ -10,23 +10,25 @@ import { SafeAreaView } from 'react-native-safe-area-context';
import styles from './Embedded.styles';

export const Embedded = () => {
const [placementIds, setPlacementIds] = useState<number[]>([]);
const [placementIdsInput, setPlacementIdsInput] = useState<string>('');
const [embeddedMessages, setEmbeddedMessages] = useState<
IterableEmbeddedMessage[]
>([]);

// Parse placement IDs from input
const parsedPlacementIds = placementIdsInput
.split(',')
.map((id) => id.trim())
.filter((id) => id !== '')
.map((id) => parseInt(id, 10))
.filter((id) => !isNaN(id));
Comment on lines +19 to +24
Copy link

Copilot AI Jan 12, 2026

Choose a reason for hiding this comment

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

The parsedPlacementIds array is recalculated on every render because it's not memoized. This could cause unnecessary re-renders and performance issues. Consider wrapping the parsing logic in useMemo to ensure it only recalculates when placementIdsInput changes.

Copilot uses AI. Check for mistakes.

const idsToFetch = parsedPlacementIds.length > 0 ? parsedPlacementIds : null;

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

const getPlacementIds = useCallback(() => {
return Iterable.embeddedManager.getPlacementIds().then((ids: unknown) => {
console.log(ids);
setPlacementIds(ids as number[]);
return ids;
});
}, []);

const startEmbeddedSession = useCallback(() => {
console.log(
'startEmbeddedSession --> check android/ios logs to check if it worked'
Expand All @@ -41,12 +43,20 @@ export const Embedded = () => {
Iterable.embeddedManager.endSession();
}, []);

const getEmbeddedMessages = useCallback((ids: number[] | null = null) => {
Iterable.embeddedManager.getMessages(ids).then((messages: IterableEmbeddedMessage[]) => {
const getEmbeddedMessages = useCallback(() => {
// Don't fetch if no IDs
if (parsedPlacementIds.length === 0) {
console.log('No placement IDs entered, button should be disabled');
return;
}

console.log('Fetching messages for placement IDs:', idsToFetch);

Iterable.embeddedManager.getMessages(idsToFetch).then((messages: IterableEmbeddedMessage[]) => {
setEmbeddedMessages(messages);
console.log(messages);
});
}, []);
}, [idsToFetch, parsedPlacementIds.length]);

const startEmbeddedImpression = useCallback(
(message: IterableEmbeddedMessage) => {
Expand Down Expand Up @@ -82,33 +92,55 @@ export const Embedded = () => {

return (
<SafeAreaView style={styles.container}>
<Text style={styles.text}>EMBEDDED</Text>
<Text style={styles.title}>Embedded</Text>
{!Iterable.embeddedManager.isEnabled && (
<View style={styles.warningContainer}>
<Text style={styles.warningText}>
⚠️ Embedded messaging is disabled. Please enable it in your Iterable config.
</Text>
</View>
)}
<Text style={styles.subtitle}>
Enter placement IDs to fetch embedded messages
</Text>
<View style={styles.utilitySection}>
<Text style={styles.text}>
Does embedded class exist? {Iterable.embeddedManager ? 'Yes' : 'No'}
</Text>
<Text style={styles.text}>
Is embedded manager enabled?{' '}
{Iterable.embeddedManager.isEnabled ? 'Yes' : 'No'}
</Text>
<Text style={styles.text}>
Placement ids: [{placementIds.join(', ')}]
</Text>
<TouchableOpacity style={styles.button} onPress={syncEmbeddedMessages}>
<Text style={styles.buttonText}>Sync messages</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={getPlacementIds}>
<Text style={styles.buttonText}>Get placement ids</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={startEmbeddedSession}>
<Text style={styles.buttonText}>Start session</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={endEmbeddedSession}>
<Text style={styles.buttonText}>End session</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={() => getEmbeddedMessages(placementIds)}>
<Text style={styles.buttonText}>Get messages</Text>
</TouchableOpacity>
<View style={styles.inputContainer}>
<Text style={styles.text}>
Placement IDs (comma-separated):
</Text>
<TextInput
style={styles.textInput}
placeholder="e.g., 1, 2, 3"
placeholderTextColor="#999"
value={placementIdsInput}
onChangeText={setPlacementIdsInput}
keyboardType="numbers-and-punctuation"
/>
<TouchableOpacity
style={[
styles.button,
parsedPlacementIds.length === 0 && styles.buttonDisabled
]}
onPress={getEmbeddedMessages}
disabled={parsedPlacementIds.length === 0}
>
<Text style={[
styles.buttonText,
parsedPlacementIds.length === 0 && styles.buttonTextDisabled
]}>
Get messages for placement ids
</Text>
</TouchableOpacity>
</View>
</View>
<View style={styles.hr} />
<ScrollView>
Expand Down
2 changes: 0 additions & 2 deletions example/src/hooks/useIterableApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,6 @@ export const IterableAppProvider: FunctionComponent<
retryBackoff: IterableRetryBackoff.linear,
};

config.enableEmbeddedMessaging = true;

config.onJwtError = (authFailure) => {
console.log('onJwtError', authFailure);

Expand Down
4 changes: 0 additions & 4 deletions src/__mocks__/MockRNIterableAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,10 +145,6 @@ export class MockRNIterableAPI {

static endEmbeddedSession = jest.fn();

static getEmbeddedPlacementIds = jest
.fn()
.mockResolvedValue([1, 2, 3] as number[]);

static syncEmbeddedMessages = jest.fn().mockResolvedValue(undefined);

static getEmbeddedMessages = jest.fn().mockResolvedValue([
Expand Down
1 change: 0 additions & 1 deletion src/api/NativeRNIterableAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,6 @@ export interface Spec extends TurboModule {
endEmbeddedSession(): void;
startEmbeddedImpression(messageId: string, placementId: number): void;
pauseEmbeddedImpression(messageId: string): void;
getEmbeddedPlacementIds(): Promise<number[]>;
getEmbeddedMessages(
placementIds: number[] | null
): Promise<EmbeddedMessage[]>;
Expand Down
8 changes: 0 additions & 8 deletions src/core/classes/IterableApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -551,14 +551,6 @@ export class IterableApi {
return RNIterableAPI.pauseEmbeddedImpression(messageId);
}

/**
* Get the embedded placement IDs.
*/
static getEmbeddedPlacementIds() {
IterableLogger.log('getEmbeddedPlacementIds');
return RNIterableAPI.getEmbeddedPlacementIds();
}

/**
* Get the embedded messages.
*
Expand Down
15 changes: 0 additions & 15 deletions src/embedded/classes/IterableEmbeddedManager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,21 +109,6 @@ describe('IterableEmbeddedManager', () => {
});
});

describe('getPlacementIds', () => {
it('should call IterableApi.getEmbeddedPlacementIds', async () => {
// WHEN getPlacementIds is called
const result = await embeddedManager.getPlacementIds();

// THEN IterableApi.getEmbeddedPlacementIds is called
expect(MockRNIterableAPI.getEmbeddedPlacementIds).toHaveBeenCalledTimes(
1
);

// AND the result is returned
expect(result).toEqual([1, 2, 3]);
});
});

describe('getMessages', () => {
it('should call IterableApi.getEmbeddedMessages with placement IDs', async () => {
// GIVEN placement IDs
Expand Down
16 changes: 0 additions & 16 deletions src/embedded/classes/IterableEmbeddedManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,22 +80,6 @@ export class IterableEmbeddedManager {
return IterableApi.syncEmbeddedMessages();
}

/**
* Retrieves a list of placement IDs for the embedded manager.
*
* [Placement Documentation](https://support.iterable.com/hc/en-us/articles/23060529977364-Embedded-Messaging-Overview#placements-and-prioritization)
*
* @example
* ```typescript
* Iterable.embeddedManager.getPlacementIds().then(placementIds => {
* console.log('Placement IDs:', placementIds);
* });
* ```
*/
getPlacementIds() {
return IterableApi.getEmbeddedPlacementIds();
}

/**
* Retrieves a list of embedded messages the user is eligible to see.
*
Expand Down
Loading