Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
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 @@ -30,6 +30,7 @@
import com.iterable.iterableapi.IterableConfig;
import com.iterable.iterableapi.IterableCustomActionHandler;
import com.iterable.iterableapi.IterableEmbeddedMessage;
import com.iterable.iterableapi.IterableEmbeddedUpdateHandler;
import com.iterable.iterableapi.IterableHelper;
import com.iterable.iterableapi.IterableInAppCloseAction;
import com.iterable.iterableapi.IterableInAppHandler;
Expand All @@ -52,7 +53,7 @@
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

public class RNIterableAPIModuleImpl implements IterableUrlHandler, IterableCustomActionHandler, IterableInAppHandler, IterableAuthHandler, IterableInAppManager.Listener {
public class RNIterableAPIModuleImpl implements IterableUrlHandler, IterableCustomActionHandler, IterableInAppHandler, IterableAuthHandler, IterableInAppManager.Listener, IterableEmbeddedUpdateHandler {
public static final String NAME = "RNIterableAPI";

private static String TAG = "RNIterableAPIModule";
Expand Down Expand Up @@ -125,6 +126,7 @@ public void initializeWithApiKey(String apiKey, ReadableMap configReadableMap, S
IterableApi.getInstance().setDeviceAttribute("reactNativeSDKVersion", version);

IterableApi.getInstance().getInAppManager().addListener(this);
IterableApi.getInstance().getEmbeddedManager().addUpdateListener(this);
IterableApi.getInstance().getEmbeddedManager().syncMessages();

// MOB-10421: Figure out what the error cases are and handle them appropriately
Expand Down Expand Up @@ -189,6 +191,7 @@ public void initialize2WithApiKey(String apiKey, ReadableMap configReadableMap,
IterableApi.getInstance().setDeviceAttribute("reactNativeSDKVersion", version);

IterableApi.getInstance().getInAppManager().addListener(this);
IterableApi.getInstance().getEmbeddedManager().addUpdateListener(this);
Comment on lines 129 to +194

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

These puts themselves as listeners to updateListener at bridge. This will bridge to receive callback when list of EmbeddedMessages change.

IterableApi.getInstance().getEmbeddedManager().syncMessages();

// MOB-10421: Figure out what the error cases are and handle them appropriately
Expand Down Expand Up @@ -781,6 +784,18 @@ public void trackEmbeddedClick(ReadableMap messageMap, String buttonId, String c
}
}

@Override
public void onMessagesUpdated() {
IterableLogger.d(TAG, "onMessagesUpdated");
sendEvent(EventName.receivedIterableEmbeddedMessagesChanged.name(), null);

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This is the callback that should trigger the call on TS level indicating its time to check local messages as sync has been performed.

}

@Override
public void onEmbeddedMessagingDisabled() {
IterableLogger.d(TAG, "onEmbeddedMessagingDisabled");
sendEvent(EventName.receivedIterableEmbeddedMessagingDisabled.name(), null);

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

During the sync, if native code recognize feature disablement, this callback will be invoked. sendEvent will then call method on EventName.receivedIterableEmbeddedMessagingDisabled. TS layer also needs to be there where TS layer have list of listener it calls to indicate this disabled feature notice.

}

// ---------------------------------------------------------------------------------------
// endregion
}
Expand All @@ -793,5 +808,6 @@ enum EventName {
handleInAppCalled,
handleUrlCalled,
receivedIterableEmbeddedMessagesChanged,
receivedIterableEmbeddedMessagingDisabled,
receivedIterableInboxChanged
}
4 changes: 4 additions & 0 deletions src/core/enums/IterableEventName.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ export enum IterableEventName {
handleAuthCalled = 'handleAuthCalled',
/** Event that fires when the Iterable inbox is updated */
receivedIterableInboxChanged = 'receivedIterableInboxChanged',
/** Event that fires when embedded messages are updated */
receivedIterableEmbeddedMessagesChanged = 'receivedIterableEmbeddedMessagesChanged',
/** Event that fires when embedded messaging is disabled */
receivedIterableEmbeddedMessagingDisabled = 'receivedIterableEmbeddedMessagingDisabled',
/** Event that fires when authentication with Iterable succeeds */
handleAuthSuccessCalled = 'handleAuthSuccessCalled',
/** Event that fires when authentication with Iterable fails */
Expand Down
82 changes: 82 additions & 0 deletions src/embedded/classes/IterableEmbeddedManager.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
import { NativeEventEmitter } from 'react-native';

import { RNIterableAPI } from '../../api';
import { IterableAction } from '../../core/classes/IterableAction';
import { IterableActionContext } from '../../core/classes/IterableActionContext';
import { IterableApi } from '../../core/classes/IterableApi';
import { IterableConfig } from '../../core/classes/IterableConfig';
import { IterableLogger } from '../../core/classes/IterableLogger';
import { IterableActionSource } from '../../core/enums/IterableActionSource';
import { IterableEventName } from '../../core/enums/IterableEventName';
import { callUrlHandler } from '../../core/utils/callUrlHandler';
import { getActionPrefix } from '../../core/utils/getActionPrefix';
import type { IterableEmbeddedMessage } from '../types/IterableEmbeddedMessage';

const RNEventEmitter = new NativeEventEmitter(RNIterableAPI);

/**
* Manages embedded messages from Iterable.
*
Expand Down Expand Up @@ -273,4 +279,80 @@ export class IterableEmbeddedManager {
callUrlHandler(this._config, clickedUrl, context);
}
}

/**
* Adds a listener for when embedded messages are updated.
*
* This event fires when the embedded message cache is synced and messages
* have changed (new messages added, existing messages removed, etc.).
*
* @param callback - Function to call when messages are updated.
* @returns An event subscription that can be used to remove the listener.
*
* @example
* ```typescript
* const subscription = Iterable.embeddedManager.addMessagesUpdatedListener(() => {
* // Refresh your UI with updated messages
* Iterable.embeddedManager.getMessages([1, 2, 3]).then(messages => {
* // Update UI with new messages
* });
* });
*
* // Later, remove the listener
* subscription.remove();
* ```
*/
addMessagesUpdatedListener(callback: () => void) {

@lposen lposen Jan 13, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think we should instead have onEmbeddedMessageUpdate and handle the unsubscribe function internally, as this is how we have done other listeners in the app.

We can then add this to the removeAllEventListeners function in Iterable.ts,

return RNEventEmitter.addListener(
IterableEventName.receivedIterableEmbeddedMessagesChanged,
callback
);
}

/**
* Adds a listener for when embedded messaging is disabled.
*
* This event fires when embedded messaging is disabled, typically due to
* subscription being inactive or invalid API key.
*
* @param callback - Function to call when embedded messaging is disabled.
* @returns An event subscription that can be used to remove the listener.
*
* @example
* ```typescript
* const subscription = Iterable.embeddedManager.addEmbeddedMessagingDisabledListener(() => {
* // Handle embedded messaging being disabled
* console.log('Embedded messaging has been disabled');
* });
*
* // Later, remove the listener
* subscription.remove();
* ```
*/
addEmbeddedMessagingDisabledListener(callback: () => void) {
return RNEventEmitter.addListener(
IterableEventName.receivedIterableEmbeddedMessagingDisabled,
callback
);
}

/**
* Removes all listeners for embedded message events.
*
* This removes all listeners for both `receivedIterableEmbeddedMessagesChanged`
* and `receivedIterableEmbeddedMessagingDisabled` events.
*
* @example
* ```typescript
* Iterable.embeddedManager.removeAllListeners();
* ```
*/
removeAllListeners() {
RNEventEmitter.removeAllListeners(
IterableEventName.receivedIterableEmbeddedMessagesChanged
);
RNEventEmitter.removeAllListeners(
IterableEventName.receivedIterableEmbeddedMessagingDisabled
);
}
}