Skip to content
Draft
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

### Updates

- Added optional placement IDs to `Iterable.embeddedManager.syncMessages()` so apps can sync embedded messages for specific placements only (SDK-751). When omitted, null, or empty, behavior matches the previous sync-all call.
- Added `Iterable.authManager.getAuthToken()` to read the JWT currently held by the native SDK (SDK-559).
- iOS: `IterableAPI.authToken`.
- Android: `IterableApi.getAuthToken()`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -762,9 +762,18 @@ public void onEmbeddedMessagingDisabled() {
// ---------------------------------------------------------------------------------------
// region Embedded messaging

public void syncEmbeddedMessages() {
IterableLogger.d(TAG, "syncEmbeddedMessages");
IterableApi.getInstance().getEmbeddedManager().syncMessages();
public void syncEmbeddedMessages(@Nullable ReadableArray placementIds) {
IterableLogger.d(TAG, "syncEmbeddedMessages for placements: " + placementIds);

if (placementIds == null || placementIds.size() == 0) {
IterableApi.getInstance().getEmbeddedManager().syncMessages();
} else {
Long[] ids = new Long[placementIds.size()];
for (int i = 0; i < placementIds.size(); i++) {
ids[i] = (long) placementIds.getInt(i);
}
IterableApi.getInstance().getEmbeddedManager().syncMessages(ids);
}
Comment thread
jferrao-itrbl marked this conversation as resolved.
}

public void startEmbeddedSession() {
Expand Down
4 changes: 2 additions & 2 deletions android/src/newarch/java/com/RNIterableAPIModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -240,8 +240,8 @@ public void pauseAuthRetries(boolean pauseRetry) {
}

@Override
public void syncEmbeddedMessages() {
moduleImpl.syncEmbeddedMessages();
public void syncEmbeddedMessages(@Nullable ReadableArray placementIds) {
moduleImpl.syncEmbeddedMessages(placementIds);
}

@Override
Expand Down
4 changes: 2 additions & 2 deletions android/src/oldarch/java/com/RNIterableAPIModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -244,8 +244,8 @@ public void pauseAuthRetries(boolean pauseRetry) {
}

@ReactMethod
public void syncEmbeddedMessages() {
moduleImpl.syncEmbeddedMessages();
public void syncEmbeddedMessages(@Nullable ReadableArray placementIds) {
moduleImpl.syncEmbeddedMessages(placementIds);
}

@ReactMethod
Expand Down
8 changes: 4 additions & 4 deletions ios/RNIterableAPI/RNIterableAPI.mm
Original file line number Diff line number Diff line change
Expand Up @@ -304,8 +304,8 @@ - (void)endEmbeddedSession {
[_swiftAPI endEmbeddedSession];
}

- (void)syncEmbeddedMessages {
[_swiftAPI syncEmbeddedMessages];
- (void)syncEmbeddedMessages:(NSArray *_Nullable)placementIds {
[_swiftAPI syncEmbeddedMessages:placementIds];
}

- (void)getEmbeddedMessages:(NSArray *_Nullable)placementIds
Expand Down Expand Up @@ -597,8 +597,8 @@ - (void)wakeApp {
[_swiftAPI endEmbeddedSession];
}

RCT_EXPORT_METHOD(syncEmbeddedMessages) {
[_swiftAPI syncEmbeddedMessages];
RCT_EXPORT_METHOD(syncEmbeddedMessages : (NSArray *_Nullable)placementIds) {
[_swiftAPI syncEmbeddedMessages:placementIds];
}

RCT_EXPORT_METHOD(getEmbeddedMessages : (NSArray *_Nullable)placementIds resolve : (RCTPromiseResolveBlock)resolve reject : (RCTPromiseRejectBlock)reject) {
Expand Down
11 changes: 8 additions & 3 deletions ios/RNIterableAPI/ReactIterableAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -535,10 +535,15 @@ import React
EmbeddedSessionManager.shared.endSession()
}

@objc(syncEmbeddedMessages)
public func syncEmbeddedMessages() {
@objc(syncEmbeddedMessages:)
public func syncEmbeddedMessages(placementIds: [NSNumber]?) {
ITBInfo()
IterableAPI.embeddedManager.syncMessages { }
if let placementIds = placementIds, !placementIds.isEmpty {
let ids = placementIds.map { $0.intValue }
IterableAPI.embeddedManager.syncMessages(placementIds: ids) { }
} else {
IterableAPI.embeddedManager.syncMessages { }
}
}

@objc(getEmbeddedMessages:resolver:rejecter:)
Expand Down
2 changes: 1 addition & 1 deletion src/api/NativeRNIterableAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ export interface Spec extends TurboModule {
pauseAuthRetries(pauseRetry: boolean): void;

// Embedded Messaging
syncEmbeddedMessages(): void;
syncEmbeddedMessages(placementIds: Array<number> | null): void;
startEmbeddedSession(): void;
endEmbeddedSession(): void;
startEmbeddedImpression(messageId: string, placementId: number): void;
Expand Down
35 changes: 32 additions & 3 deletions src/core/classes/IterableApi.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1299,13 +1299,42 @@ describe('IterableApi', () => {
});

describe('syncEmbeddedMessages', () => {
it('should call RNIterableAPI.syncEmbeddedMessages', () => {
it('should call RNIterableAPI.syncEmbeddedMessages with null when omitted', () => {
// GIVEN no parameters
// WHEN syncEmbeddedMessages is called
IterableApi.syncEmbeddedMessages();

// THEN RNIterableAPI.syncEmbeddedMessages is called
expect(MockRNIterableAPI.syncEmbeddedMessages).toBeCalled();
// THEN RNIterableAPI.syncEmbeddedMessages is called with null (sync all)
expect(MockRNIterableAPI.syncEmbeddedMessages).toBeCalledWith(null);
});

it('should call RNIterableAPI.syncEmbeddedMessages with null when passed null', () => {
// WHEN syncEmbeddedMessages is called with null
IterableApi.syncEmbeddedMessages(null);

// THEN RNIterableAPI.syncEmbeddedMessages is called with null (sync all)
expect(MockRNIterableAPI.syncEmbeddedMessages).toBeCalledWith(null);
});

it('should call RNIterableAPI.syncEmbeddedMessages with placement IDs', () => {
// GIVEN placement IDs
const placementIds = [1, 2];

// WHEN syncEmbeddedMessages is called
IterableApi.syncEmbeddedMessages(placementIds);

// THEN RNIterableAPI.syncEmbeddedMessages is called with placement IDs
expect(MockRNIterableAPI.syncEmbeddedMessages).toBeCalledWith(
placementIds
);
});

it('should call RNIterableAPI.syncEmbeddedMessages with empty array for sync all', () => {
// WHEN syncEmbeddedMessages is called with an empty array
IterableApi.syncEmbeddedMessages([]);

// THEN the empty array is forwarded (native syncs all placements)
expect(MockRNIterableAPI.syncEmbeddedMessages).toBeCalledWith([]);
});
});

Expand Down
8 changes: 5 additions & 3 deletions src/core/classes/IterableApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -551,9 +551,11 @@ export class IterableApi {
/**
* Syncs embedded local cache with the server.
*/
static syncEmbeddedMessages() {
IterableLogger.log('syncEmbeddedMessages');
return RNIterableAPI.syncEmbeddedMessages();
static syncEmbeddedMessages(placementIds?: number[] | null) {
IterableLogger.log('syncEmbeddedMessages: ', placementIds);
return RNIterableAPI.syncEmbeddedMessages(
placementIds === undefined ? null : placementIds
);
}

/**
Expand Down
37 changes: 35 additions & 2 deletions src/embedded/classes/IterableEmbeddedManager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,16 +97,49 @@ describe('IterableEmbeddedManager', () => {
});

describe('syncMessages', () => {
it('should call IterableApi.syncEmbeddedMessages', async () => {
it('should call IterableApi.syncEmbeddedMessages with null when omitted', async () => {
// WHEN syncMessages is called
const result = await embeddedManager.syncMessages();

// THEN IterableApi.syncEmbeddedMessages is called
// THEN IterableApi.syncEmbeddedMessages is called with null
expect(MockRNIterableAPI.syncEmbeddedMessages).toHaveBeenCalledTimes(1);
expect(MockRNIterableAPI.syncEmbeddedMessages).toHaveBeenCalledWith(null);

// AND the result is returned
expect(result).toBeUndefined();
});

it('should call IterableApi.syncEmbeddedMessages with placement IDs', () => {
// GIVEN placement IDs
const placementIds = [1, 2];

// WHEN syncMessages is called
embeddedManager.syncMessages(placementIds);

// THEN IterableApi.syncEmbeddedMessages is called with placement IDs
expect(MockRNIterableAPI.syncEmbeddedMessages).toHaveBeenCalledTimes(1);
expect(MockRNIterableAPI.syncEmbeddedMessages).toHaveBeenCalledWith(
placementIds
);
});

it('should call IterableApi.syncEmbeddedMessages with null placement IDs', () => {
// WHEN syncMessages is called with null
embeddedManager.syncMessages(null);

// THEN IterableApi.syncEmbeddedMessages is called with null
expect(MockRNIterableAPI.syncEmbeddedMessages).toHaveBeenCalledTimes(1);
expect(MockRNIterableAPI.syncEmbeddedMessages).toHaveBeenCalledWith(null);
});

it('should call IterableApi.syncEmbeddedMessages with empty placement IDs', () => {
// WHEN syncMessages is called with an empty array
embeddedManager.syncMessages([]);

// THEN the empty array is forwarded (native syncs all placements)
expect(MockRNIterableAPI.syncEmbeddedMessages).toHaveBeenCalledTimes(1);
expect(MockRNIterableAPI.syncEmbeddedMessages).toHaveBeenCalledWith([]);
});
});

describe('getMessages', () => {
Expand Down
8 changes: 6 additions & 2 deletions src/embedded/classes/IterableEmbeddedManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,17 @@ export class IterableEmbeddedManager {
*
* However, do not poll for new embedded messages at a regular interval.
*
* @param placementIds - Optional placement IDs to sync. When omitted, null, or
* empty, syncs all placements.
*
* @example
* ```typescript
* IterableEmbeddedManager.syncMessages();
* IterableEmbeddedManager.syncMessages([1, 2, 3]);
* ```
*/
syncMessages() {
return IterableApi.syncEmbeddedMessages();
syncMessages(placementIds?: number[] | null) {
return IterableApi.syncEmbeddedMessages(placementIds);
}

/**
Expand Down
Loading