From 1bee2d631af79d553ab7b2d0bb5c8e83e9aec085 Mon Sep 17 00:00:00 2001 From: Loren Posen Date: Mon, 13 Oct 2025 09:38:58 -0700 Subject: [PATCH 1/8] feat: add session management methods to IterableEmbeddedManager --- .../classes/IterableEmbeddedManager.ts | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/embedded/classes/IterableEmbeddedManager.ts b/src/embedded/classes/IterableEmbeddedManager.ts index c4f8ae229..b485280cf 100644 --- a/src/embedded/classes/IterableEmbeddedManager.ts +++ b/src/embedded/classes/IterableEmbeddedManager.ts @@ -1,4 +1,5 @@ import { IterableApi } from '../../core/classes/IterableApi'; +import { IterableLogger } from '../../core/classes/IterableLogger'; /** * Manages embedded messages from Iterable. @@ -25,4 +26,26 @@ export class IterableEmbeddedManager { getPlacementIds() { return IterableApi.getEmbeddedPlacementIds(); } + + /** + * Starts a session, or a period of time when a user is on a screen or page + * that can display embedded messages. + */ + startSession() { + IterableLogger.log('IterableEmbeddedManager.startSession'); + } + + /** + * Ends a session. + */ + endSession() { + IterableLogger.log('IterableEmbeddedManager.endSession'); + } + + /** + * Tracks an embedded session. + */ + trackSession() { + IterableLogger.log('IterableEmbeddedManager.trackSession'); + } } From 0ba0b7f925ede49b6dcc8277e5c87e698acc0274 Mon Sep 17 00:00:00 2001 From: Loren Posen Date: Mon, 13 Oct 2025 10:40:22 -0700 Subject: [PATCH 2/8] docs: enhance session management method documentation in IterableEmbeddedManager --- .../classes/IterableEmbeddedManager.ts | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/embedded/classes/IterableEmbeddedManager.ts b/src/embedded/classes/IterableEmbeddedManager.ts index b485280cf..df52ffd02 100644 --- a/src/embedded/classes/IterableEmbeddedManager.ts +++ b/src/embedded/classes/IterableEmbeddedManager.ts @@ -28,8 +28,18 @@ export class IterableEmbeddedManager { } /** - * Starts a session, or a period of time when a user is on a screen or page - * that can display embedded messages. + * Starts a session. + * + * As session is a period of time when a user is on a screen or page that can + * display embedded messages. + * + * When a user comes to a screen or page in your app where embedded messages + * are displayed (in one or more placements), a session should be started. + * + * @example + * ```typescript + * IterableEmbeddedManager.startSession(); + * ``` */ startSession() { IterableLogger.log('IterableEmbeddedManager.startSession'); @@ -37,6 +47,15 @@ export class IterableEmbeddedManager { /** * Ends a session. + * + * When a user leaves a screen in your app where embedded messages are + * displayed, the session should be ended. This causes the SDK to send + * session and impression data back to the server. + * + * @example + * ```typescript + * IterableEmbeddedManager.endSession(); + * ``` */ endSession() { IterableLogger.log('IterableEmbeddedManager.endSession'); @@ -44,6 +63,11 @@ export class IterableEmbeddedManager { /** * Tracks an embedded session. + * + * @example + * ```typescript + * IterableEmbeddedManager.trackSession(); + * ``` */ trackSession() { IterableLogger.log('IterableEmbeddedManager.trackSession'); From 24d5a7042f373fb1873fd68d232c7416a9bf6247 Mon Sep 17 00:00:00 2001 From: Loren Posen Date: Mon, 13 Oct 2025 10:55:15 -0700 Subject: [PATCH 3/8] feat: add startEmbeddedSession method --- .../iterable/reactnative/RNIterableAPIModuleImpl.java | 5 +++++ android/src/newarch/java/com/RNIterableAPIModule.java | 5 +++++ android/src/oldarch/java/com/RNIterableAPIModule.java | 5 +++++ example/src/components/Embedded/Embedded.tsx | 10 ++++++++++ src/api/NativeRNIterableAPI.ts | 1 + src/core/classes/IterableApi.ts | 8 ++++++++ src/embedded/classes/IterableEmbeddedManager.ts | 2 +- 7 files changed, 35 insertions(+), 1 deletion(-) diff --git a/android/src/main/java/com/iterable/reactnative/RNIterableAPIModuleImpl.java b/android/src/main/java/com/iterable/reactnative/RNIterableAPIModuleImpl.java index fcbbbb2e1..f9bddf2c5 100644 --- a/android/src/main/java/com/iterable/reactnative/RNIterableAPIModuleImpl.java +++ b/android/src/main/java/com/iterable/reactnative/RNIterableAPIModuleImpl.java @@ -650,6 +650,11 @@ public void onInboxUpdated() { // --------------------------------------------------------------------------------------- // region Embedded messaging + + public void startEmbeddedSession() { + IterableApi.getInstance().getEmbeddedManager().getEmbeddedSessionManager().startSession(); + } + public void getEmbeddedPlacementIds(Promise promise) { IterableLogger.d(TAG, "getEmbeddedPlacementIds"); try { diff --git a/android/src/newarch/java/com/RNIterableAPIModule.java b/android/src/newarch/java/com/RNIterableAPIModule.java index 50e814f0b..3f649f0c6 100644 --- a/android/src/newarch/java/com/RNIterableAPIModule.java +++ b/android/src/newarch/java/com/RNIterableAPIModule.java @@ -224,6 +224,11 @@ public void pauseAuthRetries(boolean pauseRetry) { moduleImpl.pauseAuthRetries(pauseRetry); } + @Override + public void startEmbeddedSession() { + moduleImpl.startEmbeddedSession(); + } + @Override public void getEmbeddedPlacementIds(Promise promise) { moduleImpl.getEmbeddedPlacementIds(promise); diff --git a/android/src/oldarch/java/com/RNIterableAPIModule.java b/android/src/oldarch/java/com/RNIterableAPIModule.java index 4555fd71b..9da39c755 100644 --- a/android/src/oldarch/java/com/RNIterableAPIModule.java +++ b/android/src/oldarch/java/com/RNIterableAPIModule.java @@ -228,6 +228,11 @@ public void pauseAuthRetries(boolean pauseRetry) { moduleImpl.pauseAuthRetries(pauseRetry); } + @ReactMethod + public void startEmbeddedSession() { + moduleImpl.startEmbeddedSession(); + } + @ReactMethod public void getEmbeddedPlacementIds(Promise promise) { moduleImpl.getEmbeddedPlacementIds(promise); diff --git a/example/src/components/Embedded/Embedded.tsx b/example/src/components/Embedded/Embedded.tsx index 39707e2ad..71962f0a7 100644 --- a/example/src/components/Embedded/Embedded.tsx +++ b/example/src/components/Embedded/Embedded.tsx @@ -13,6 +13,13 @@ export const Embedded = () => { }); }, []); + const startEmbeddedSession = useCallback(() => { + console.log( + 'startEmbeddedSession --> check android/ios logs to check if it worked' + ); + Iterable.embeddedManager.startSession(); + }, []); + return ( EMBEDDED @@ -29,6 +36,9 @@ export const Embedded = () => { Get placement ids + + Start embedded session + ); }; diff --git a/src/api/NativeRNIterableAPI.ts b/src/api/NativeRNIterableAPI.ts index 9dd2af2b7..e157a403f 100644 --- a/src/api/NativeRNIterableAPI.ts +++ b/src/api/NativeRNIterableAPI.ts @@ -119,6 +119,7 @@ export interface Spec extends TurboModule { pauseAuthRetries(pauseRetry: boolean): void; // Embedded Messaging + startEmbeddedSession(): void; getEmbeddedPlacementIds(): Promise; // Wake app -- android only diff --git a/src/core/classes/IterableApi.ts b/src/core/classes/IterableApi.ts index 9825f42ae..e005d32f1 100644 --- a/src/core/classes/IterableApi.ts +++ b/src/core/classes/IterableApi.ts @@ -510,6 +510,14 @@ export class IterableApi { // ======================= EMBEDDED ===================== // // ====================================================== // + /** + * Starts an embedded session. + */ + static startEmbeddedSession() { + IterableLogger.log('startEmbeddedSession'); + return RNIterableAPI.startEmbeddedSession(); + } + /** * Get the embedded placement IDs. */ diff --git a/src/embedded/classes/IterableEmbeddedManager.ts b/src/embedded/classes/IterableEmbeddedManager.ts index df52ffd02..0983303e1 100644 --- a/src/embedded/classes/IterableEmbeddedManager.ts +++ b/src/embedded/classes/IterableEmbeddedManager.ts @@ -42,7 +42,7 @@ export class IterableEmbeddedManager { * ``` */ startSession() { - IterableLogger.log('IterableEmbeddedManager.startSession'); + return IterableApi.startEmbeddedSession(); } /** From be8998a0630693474df2723b547641ea33ad446a Mon Sep 17 00:00:00 2001 From: Loren Posen Date: Mon, 13 Oct 2025 10:59:42 -0700 Subject: [PATCH 4/8] feat: add endEmbeddedSession method and update session management in RNIterableAPIModule --- .../iterable/reactnative/RNIterableAPIModuleImpl.java | 6 ++++++ android/src/newarch/java/com/RNIterableAPIModule.java | 5 +++++ android/src/oldarch/java/com/RNIterableAPIModule.java | 5 +++++ example/src/components/Embedded/Embedded.tsx | 10 ++++++++++ src/api/NativeRNIterableAPI.ts | 1 + src/core/classes/IterableApi.ts | 8 ++++++++ src/embedded/classes/IterableEmbeddedManager.ts | 2 +- 7 files changed, 36 insertions(+), 1 deletion(-) diff --git a/android/src/main/java/com/iterable/reactnative/RNIterableAPIModuleImpl.java b/android/src/main/java/com/iterable/reactnative/RNIterableAPIModuleImpl.java index f9bddf2c5..ece9d8737 100644 --- a/android/src/main/java/com/iterable/reactnative/RNIterableAPIModuleImpl.java +++ b/android/src/main/java/com/iterable/reactnative/RNIterableAPIModuleImpl.java @@ -652,9 +652,15 @@ public void onInboxUpdated() { // region Embedded messaging public void startEmbeddedSession() { + IterableLogger.d(TAG, "startEmbeddedSession"); IterableApi.getInstance().getEmbeddedManager().getEmbeddedSessionManager().startSession(); } + public void endEmbeddedSession() { + IterableLogger.d(TAG, "endEmbeddedSession"); + IterableApi.getInstance().getEmbeddedManager().getEmbeddedSessionManager().endSession(); + } + public void getEmbeddedPlacementIds(Promise promise) { IterableLogger.d(TAG, "getEmbeddedPlacementIds"); try { diff --git a/android/src/newarch/java/com/RNIterableAPIModule.java b/android/src/newarch/java/com/RNIterableAPIModule.java index 3f649f0c6..4c67af4e5 100644 --- a/android/src/newarch/java/com/RNIterableAPIModule.java +++ b/android/src/newarch/java/com/RNIterableAPIModule.java @@ -229,6 +229,11 @@ public void startEmbeddedSession() { moduleImpl.startEmbeddedSession(); } + @Override + public void endEmbeddedSession() { + moduleImpl.endEmbeddedSession(); + } + @Override public void getEmbeddedPlacementIds(Promise promise) { moduleImpl.getEmbeddedPlacementIds(promise); diff --git a/android/src/oldarch/java/com/RNIterableAPIModule.java b/android/src/oldarch/java/com/RNIterableAPIModule.java index 9da39c755..868f4051d 100644 --- a/android/src/oldarch/java/com/RNIterableAPIModule.java +++ b/android/src/oldarch/java/com/RNIterableAPIModule.java @@ -233,6 +233,11 @@ public void startEmbeddedSession() { moduleImpl.startEmbeddedSession(); } + @ReactMethod + public void endEmbeddedSession() { + moduleImpl.endEmbeddedSession(); + } + @ReactMethod public void getEmbeddedPlacementIds(Promise promise) { moduleImpl.getEmbeddedPlacementIds(promise); diff --git a/example/src/components/Embedded/Embedded.tsx b/example/src/components/Embedded/Embedded.tsx index 71962f0a7..efedac721 100644 --- a/example/src/components/Embedded/Embedded.tsx +++ b/example/src/components/Embedded/Embedded.tsx @@ -20,6 +20,13 @@ export const Embedded = () => { Iterable.embeddedManager.startSession(); }, []); + const endEmbeddedSession = useCallback(() => { + console.log( + 'endEmbeddedSession --> check android/ios logs to check if it worked' + ); + Iterable.embeddedManager.endSession(); + }, []); + return ( EMBEDDED @@ -39,6 +46,9 @@ export const Embedded = () => { Start embedded session + + End embedded session + ); }; diff --git a/src/api/NativeRNIterableAPI.ts b/src/api/NativeRNIterableAPI.ts index e157a403f..931be6f29 100644 --- a/src/api/NativeRNIterableAPI.ts +++ b/src/api/NativeRNIterableAPI.ts @@ -120,6 +120,7 @@ export interface Spec extends TurboModule { // Embedded Messaging startEmbeddedSession(): void; + endEmbeddedSession(): void; getEmbeddedPlacementIds(): Promise; // Wake app -- android only diff --git a/src/core/classes/IterableApi.ts b/src/core/classes/IterableApi.ts index e005d32f1..84c8f3a7a 100644 --- a/src/core/classes/IterableApi.ts +++ b/src/core/classes/IterableApi.ts @@ -518,6 +518,14 @@ export class IterableApi { return RNIterableAPI.startEmbeddedSession(); } + /** + * Ends an embedded session. + */ + static endEmbeddedSession() { + IterableLogger.log('endEmbeddedSession'); + return RNIterableAPI.endEmbeddedSession(); + } + /** * Get the embedded placement IDs. */ diff --git a/src/embedded/classes/IterableEmbeddedManager.ts b/src/embedded/classes/IterableEmbeddedManager.ts index 0983303e1..9a5f14487 100644 --- a/src/embedded/classes/IterableEmbeddedManager.ts +++ b/src/embedded/classes/IterableEmbeddedManager.ts @@ -58,7 +58,7 @@ export class IterableEmbeddedManager { * ``` */ endSession() { - IterableLogger.log('IterableEmbeddedManager.endSession'); + return IterableApi.endEmbeddedSession(); } /** From cbb547f84ac6aad853774f1ee5f5207e741bd300 Mon Sep 17 00:00:00 2001 From: Loren Posen Date: Mon, 13 Oct 2025 11:04:24 -0700 Subject: [PATCH 5/8] docs: update IterableEmbeddedManager documentation to clarify enableEmbeddedMessaging flag --- .../classes/IterableEmbeddedManager.ts | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/src/embedded/classes/IterableEmbeddedManager.ts b/src/embedded/classes/IterableEmbeddedManager.ts index 9a5f14487..5515cb6ab 100644 --- a/src/embedded/classes/IterableEmbeddedManager.ts +++ b/src/embedded/classes/IterableEmbeddedManager.ts @@ -1,5 +1,4 @@ import { IterableApi } from '../../core/classes/IterableApi'; -import { IterableLogger } from '../../core/classes/IterableLogger'; /** * Manages embedded messages from Iterable. @@ -15,6 +14,9 @@ import { IterableLogger } from '../../core/classes/IterableLogger'; export class IterableEmbeddedManager { /** * Whether the embedded manager is enabled. + * + * This is set through the `enableEmbeddedMessaging` flag in the + * `IterableConfig` class. */ isEnabled = false; @@ -52,6 +54,9 @@ export class IterableEmbeddedManager { * displayed, the session should be ended. This causes the SDK to send * session and impression data back to the server. * + * A session is tracked when it is ended, so you should be able to find + * tracking data after this method is called. + * * @example * ```typescript * IterableEmbeddedManager.endSession(); @@ -60,16 +65,4 @@ export class IterableEmbeddedManager { endSession() { return IterableApi.endEmbeddedSession(); } - - /** - * Tracks an embedded session. - * - * @example - * ```typescript - * IterableEmbeddedManager.trackSession(); - * ``` - */ - trackSession() { - IterableLogger.log('IterableEmbeddedManager.trackSession'); - } } From efbda573175bd0ca3031d377a2c3e0e5f092dbae Mon Sep 17 00:00:00 2001 From: Loren Posen Date: Tue, 18 Nov 2025 23:00:24 -0800 Subject: [PATCH 6/8] feat: update login function to support JWT token retrieval and enhance user identification --- example/src/hooks/useIterableApp.tsx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/example/src/hooks/useIterableApp.tsx b/example/src/hooks/useIterableApp.tsx index 53de3d126..2a392dd0d 100644 --- a/example/src/hooks/useIterableApp.tsx +++ b/example/src/hooks/useIterableApp.tsx @@ -123,7 +123,7 @@ export const IterableAppProvider: FunctionComponent< return jwtToken; }, [userId]); - const login = useCallback(() => { + const login = useCallback(async () => { const id = userId ?? process.env.ITBL_ID; if (!id) return Promise.reject('No User ID or Email set'); @@ -132,12 +132,18 @@ export const IterableAppProvider: FunctionComponent< const fn = getIsEmail(id) ? Iterable.setEmail : Iterable.setUserId; - fn(id); + let token; + + if (process.env.ITBL_IS_JWT_ENABLED === 'true' && process.env.ITBL_JWT_SECRET) { + token = await getJwtToken(); + } + + fn(id, token); setIsLoggedIn(true); setLoginInProgress(false); return Promise.resolve(true); - }, [userId]); + }, [getJwtToken, userId]); const initialize = useCallback( (navigation: Navigation) => { From 67e116b94e19790c06675442c41a0484b93dc486 Mon Sep 17 00:00:00 2001 From: Loren Posen Date: Tue, 18 Nov 2025 23:04:06 -0800 Subject: [PATCH 7/8] fix: update example usage of startSession and endSession methods in IterableEmbeddedManager --- src/embedded/classes/IterableEmbeddedManager.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/embedded/classes/IterableEmbeddedManager.ts b/src/embedded/classes/IterableEmbeddedManager.ts index 91cfc9ef5..d36d11885 100644 --- a/src/embedded/classes/IterableEmbeddedManager.ts +++ b/src/embedded/classes/IterableEmbeddedManager.ts @@ -56,7 +56,7 @@ export class IterableEmbeddedManager { * * @example * ```typescript - * IterableEmbeddedManager.startSession(); + * Iterable.embeddedManager.startSession(); * ``` */ startSession() { @@ -75,7 +75,7 @@ export class IterableEmbeddedManager { * * @example * ```typescript - * IterableEmbeddedManager.endSession(); + * Iterable.embeddedManager.endSession(); * ``` */ endSession() { From bab2b356b561541218505e6601b8a27248f6d472 Mon Sep 17 00:00:00 2001 From: Loren Posen Date: Tue, 18 Nov 2025 23:06:33 -0800 Subject: [PATCH 8/8] test: add unit tests for new embedded session methods in IterableEmbeddedManager --- src/__mocks__/MockRNIterableAPI.ts | 8 ++++ .../classes/IterableEmbeddedManager.test.ts | 43 +++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/src/__mocks__/MockRNIterableAPI.ts b/src/__mocks__/MockRNIterableAPI.ts index c7f325677..fc7ed502f 100644 --- a/src/__mocks__/MockRNIterableAPI.ts +++ b/src/__mocks__/MockRNIterableAPI.ts @@ -129,6 +129,14 @@ export class MockRNIterableAPI { static getHtmlInAppContentForMessage = jest.fn(); + static startEmbeddedSession = jest.fn(); + + static endEmbeddedSession = jest.fn(); + + static getEmbeddedPlacementIds = jest + .fn() + .mockResolvedValue([1, 2, 3] as number[]); + // set messages function is to set the messages static property // this is for testing purposes only static setMessages(messages: IterableInAppMessage[]): void { diff --git a/src/embedded/classes/IterableEmbeddedManager.test.ts b/src/embedded/classes/IterableEmbeddedManager.test.ts index 96a09ddf4..c05e38533 100644 --- a/src/embedded/classes/IterableEmbeddedManager.test.ts +++ b/src/embedded/classes/IterableEmbeddedManager.test.ts @@ -1,10 +1,18 @@ +import { MockRNIterableAPI } from '../../__mocks__/MockRNIterableAPI'; import { IterableEmbeddedManager } from './IterableEmbeddedManager'; +// Mock the RNIterableAPI module +jest.mock('../../api', () => ({ + __esModule: true, + default: MockRNIterableAPI, +})); + describe('IterableEmbeddedManager', () => { let embeddedManager: IterableEmbeddedManager; beforeEach(() => { embeddedManager = new IterableEmbeddedManager(); + jest.clearAllMocks(); }); describe('isEnabled', () => { @@ -55,5 +63,40 @@ describe('IterableEmbeddedManager', () => { expect(embeddedManager.isEnabled).toBe(false); }); }); + + 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('startSession', () => { + it('should call IterableApi.startEmbeddedSession', () => { + // WHEN startSession is called + embeddedManager.startSession(); + + // THEN IterableApi.startEmbeddedSession is called + expect(MockRNIterableAPI.startEmbeddedSession).toHaveBeenCalledTimes(1); + }); + }); + + describe('endSession', () => { + it('should call IterableApi.endEmbeddedSession', () => { + // WHEN endSession is called + embeddedManager.endSession(); + + // THEN IterableApi.endEmbeddedSession is called + expect(MockRNIterableAPI.endEmbeddedSession).toHaveBeenCalledTimes(1); + }); + }); });