diff --git a/example/src/components/Embedded/Embedded.tsx b/example/src/components/Embedded/Embedded.tsx index 785d722d6..9c67cb913 100644 --- a/example/src/components/Embedded/Embedded.tsx +++ b/example/src/components/Embedded/Embedded.tsx @@ -41,14 +41,12 @@ export const Embedded = () => { Iterable.embeddedManager.endSession(); }, []); - const getEmbeddedMessages = useCallback(() => { - getPlacementIds() - .then((ids: number[]) => Iterable.embeddedManager.getMessages(ids)) - .then((messages: IterableEmbeddedMessage[]) => { + const getEmbeddedMessages = useCallback((ids: number[] | null = null) => { + Iterable.embeddedManager.getMessages(ids).then((messages: IterableEmbeddedMessage[]) => { setEmbeddedMessages(messages); console.log(messages); }); - }, [getPlacementIds]); + }, []); const startEmbeddedImpression = useCallback( (message: IterableEmbeddedMessage) => { @@ -108,7 +106,7 @@ export const Embedded = () => { End session - + getEmbeddedMessages(placementIds)}> Get messages diff --git a/ios/RNIterableAPI/RNIterableAPI.mm b/ios/RNIterableAPI/RNIterableAPI.mm index 503e52fe2..4f05929de 100644 --- a/ios/RNIterableAPI/RNIterableAPI.mm +++ b/ios/RNIterableAPI/RNIterableAPI.mm @@ -285,6 +285,16 @@ - (void)endEmbeddedSession { [_swiftAPI endEmbeddedSession]; } +- (void)syncEmbeddedMessages { + [_swiftAPI syncEmbeddedMessages]; +} + +- (void)getEmbeddedMessages:(NSArray *_Nullable)placementIds + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject { + [_swiftAPI getEmbeddedMessages:placementIds resolver:resolve rejecter:reject]; +} + - (void)wakeApp { // Placeholder function -- this method is only used in Android } @@ -523,6 +533,14 @@ - (void)wakeApp { [_swiftAPI endEmbeddedSession]; } +RCT_EXPORT_METHOD(syncEmbeddedMessages) { + [_swiftAPI syncEmbeddedMessages]; +} + +RCT_EXPORT_METHOD(getEmbeddedMessages : (NSArray *_Nullable)placementIds resolve : (RCTPromiseResolveBlock)resolve reject : (RCTPromiseRejectBlock)reject) { + [_swiftAPI getEmbeddedMessages:placementIds resolver:resolve rejecter:reject]; +} + RCT_EXPORT_METHOD(wakeApp) { // Placeholder function -- this method is only used in Android } diff --git a/ios/RNIterableAPI/ReactIterableAPI.swift b/ios/RNIterableAPI/ReactIterableAPI.swift index fb4af214d..15ed7f14b 100644 --- a/ios/RNIterableAPI/ReactIterableAPI.swift +++ b/ios/RNIterableAPI/ReactIterableAPI.swift @@ -507,6 +507,36 @@ import React EmbeddedSessionManager.shared.endSession() } + @objc(syncEmbeddedMessages) + public func syncEmbeddedMessages() { + ITBInfo() + IterableAPI.embeddedManager.syncMessages { } + } + + @objc(getEmbeddedMessages:resolver:rejecter:) + public func getEmbeddedMessages( + placementIds: [NSNumber]?, resolver: RCTPromiseResolveBlock, rejecter: RCTPromiseRejectBlock + ) { + ITBInfo() + var messages: [IterableEmbeddedMessage] = [] + + if let placementIds = placementIds, !placementIds.isEmpty { + // Get messages for specific placement IDs + for placementId in placementIds { + let placementMessages = IterableAPI.embeddedManager.getMessages( + for: placementId.intValue + ) + messages.append(contentsOf: placementMessages) + } + } else { + // Get all messages from all placements + // getMessages() without parameters flattens all placement messages into a single array + messages = IterableAPI.embeddedManager.getMessages() + } + + resolver(messages.map { $0.toDict() }) + } + // MARK: Private private var shouldEmit = false private let _methodQueue = DispatchQueue(label: String(describing: ReactIterableAPI.self)) diff --git a/ios/RNIterableAPI/Serialization.swift b/ios/RNIterableAPI/Serialization.swift index 503427d5d..fee4c49b6 100644 --- a/ios/RNIterableAPI/Serialization.swift +++ b/ios/RNIterableAPI/Serialization.swift @@ -283,3 +283,33 @@ extension InboxImpressionTracker.RowInfo { return rows.compactMap(InboxImpressionTracker.RowInfo.from(dict:)) } } + +extension IterableEmbeddedMessage { + func toDict() -> [AnyHashable: Any]? { + var dict = [AnyHashable: Any]() + + // CRITICAL: Metadata is required - fail if missing + guard let metadataDict = SerializationUtil.encodableToDictionary(encodable: metadata) else { + ITBError("Failed to serialize embedded message metadata. Dropping invalid message.") + return nil + } + dict["metadata"] = metadataDict + + // IMPORTANT: Elements are optional, but if present and fail to serialize, that's bad + if let elements = elements { + if let elementsDict = SerializationUtil.encodableToDictionary(encodable: elements) { + dict["elements"] = elementsDict + } else { + ITBError("Failed to serialize embedded message elements. Message will not be displayable.") + return nil + } + } + + // Payload doesn't need serialization - it's already a dictionary + if let payload = payload { + dict["payload"] = payload + } + + return dict + } +}