diff --git a/src/__tests__/IterableInApp.test.ts b/src/__tests__/IterableInApp.test.ts index 282d83e01..b4a157413 100644 --- a/src/__tests__/IterableInApp.test.ts +++ b/src/__tests__/IterableInApp.test.ts @@ -1,7 +1,6 @@ import { NativeEventEmitter } from 'react-native'; import { IterableLogger } from '../core'; -import { IterableInAppManager } from '../inApp'; import { MockRNIterableAPI } from '../__mocks__/MockRNIterableAPI'; @@ -202,10 +201,8 @@ describe('Iterable In App', () => { // WHEN the simulated local queue is set to the in-app messages MockRNIterableAPI.setMessages(messages); - const inAppManager = new IterableInAppManager(); - - // THEN Iterable,inAppManager.getMessages returns the list of in-app messages - return await inAppManager.getMessages().then((messagesObtained) => { + // THEN Iterable.inAppManager.getMessages returns the list of in-app messages + return await Iterable.inAppManager?.getMessages().then((messagesObtained) => { expect(messagesObtained).toEqual(messages); }); }); @@ -224,9 +221,8 @@ describe('Iterable In App', () => { // WHEN the simulated clicked url is set to the clicked url MockRNIterableAPI.setClickedUrl(clickedUrl); - const inAppManager = new IterableInAppManager(); // THEN Iterable,inAppManager.showMessage returns the simulated clicked url - return await inAppManager.showMessage(message, consume).then((url) => { + return await Iterable.inAppManager?.showMessage(message, consume).then((url) => { expect(url).toEqual(clickedUrl); }); }); @@ -242,10 +238,9 @@ describe('Iterable In App', () => { const location: IterableInAppLocation = IterableInAppLocation.inApp; const source: IterableInAppDeleteSource = IterableInAppDeleteSource.deleteButton; - const inAppManager = new IterableInAppManager(); // WHEN Iterable.inAppManager.removeMessage is called - inAppManager.removeMessage(message, location, source); + Iterable.inAppManager?.removeMessage(message, location, source); // THEN corresponding method is called on MockIterableAPI with appropriate parameters expect(MockRNIterableAPI.removeMessage).toBeCalledWith( @@ -266,8 +261,7 @@ describe('Iterable In App', () => { const read: boolean = true; // WHEN Iterable.inAppManager.setReadForMessage is called - const inAppManager = new IterableInAppManager(); - inAppManager.setReadForMessage(message, read); + Iterable.inAppManager?.setReadForMessage(message, read); // THEN corresponding method is called on MockRNIterableAPI with appropriate parameters expect(MockRNIterableAPI.setReadForMessage).toBeCalledWith( @@ -281,8 +275,7 @@ describe('Iterable In App', () => { const paused: boolean = true; // WHEN Iterable.inAppManager.setAutoDisplayPaused is called - const inAppManager = new IterableInAppManager(); - inAppManager.setAutoDisplayPaused(paused); + Iterable.inAppManager?.setAutoDisplayPaused(paused); // THEN corresponding method is called on MockRNIterableAPI with appropriate parameters expect(MockRNIterableAPI.setAutoDisplayPaused).toBeCalledWith(paused); diff --git a/src/core/classes/Iterable.ts b/src/core/classes/Iterable.ts index 5b8b07fff..704403099 100644 --- a/src/core/classes/Iterable.ts +++ b/src/core/classes/Iterable.ts @@ -15,6 +15,9 @@ import { IterableInAppDeleteSource } from '../../inApp/enums/IterableInAppDelete import { IterableInAppLocation } from '../../inApp/enums/IterableInAppLocation'; import { IterableAuthResponseResult, IterableEventName } from '../enums'; +// Add this type-only import to avoid circular dependency +import type { IterableInAppManager } from '../../inApp/classes/IterableInAppManager'; + import { IterableAction } from './IterableAction'; import { IterableActionContext } from './IterableActionContext'; import { IterableAttributionInfo } from './IterableAttributionInfo'; @@ -56,6 +59,36 @@ export class Iterable { */ static savedConfig: IterableConfig = new IterableConfig(); + /** + * In-app message manager for the current user. + * + * This property provides access to in-app message functionality including + * retrieving messages, displaying messages, removing messages, and more. + * + * @example + * ```typescript + * // Get all in-app messages + * Iterable.inAppManager.getMessages().then(messages => { + * console.log('Messages:', messages); + * }); + * + * // Show a specific message + * Iterable.inAppManager.showMessage(message, true); + * ``` + */ + static get inAppManager() { + // Lazy initialization to avoid circular dependency + if (!this._inAppManager) { + // Import here to avoid circular dependency at module level + // eslint-disable-next-line @typescript-eslint/no-var-requires,@typescript-eslint/no-require-imports + const { IterableInAppManager } = require('../../inApp/classes/IterableInAppManager'); + this._inAppManager = new IterableInAppManager(); + } + return this._inAppManager; + } + + private static _inAppManager: IterableInAppManager | undefined; + /** * Initializes the Iterable React Native SDK in your app's Javascript or Typescript code. * diff --git a/src/inApp/classes/IterableInAppManager.ts b/src/inApp/classes/IterableInAppManager.ts index 640b99d50..a96782b13 100644 --- a/src/inApp/classes/IterableInAppManager.ts +++ b/src/inApp/classes/IterableInAppManager.ts @@ -77,7 +77,7 @@ export class IterableInAppManager { * }); * ``` * - * @param message - The message to show (an {@link_IterableInAppMessage} object) + * @param message - The message to show (an {@link IterableInAppMessage} object) * @param consume - Whether or not the message should be consumed from the user's message queue after being shown. This should be defaulted to true. * * @returns A Promise that resolves to the URL of the button or link the user tapped to close the in-app message.