From 376abd19bb73666492bbcb0bbf5a5fe1e80e1e1d Mon Sep 17 00:00:00 2001 From: Evan Greer Date: Wed, 4 Jun 2025 14:36:22 -0600 Subject: [PATCH 01/30] feat: updates bridge --- .../reactnative/RNIterableAPIModule.java | 30 +++++++++++++++++++ ios/RNIterableAPI/RNIterableAPI.m | 5 ++++ ios/RNIterableAPI/ReactIterableAPI.swift | 16 ++++++++++ 3 files changed, 51 insertions(+) diff --git a/android/src/main/java/com/iterable/reactnative/RNIterableAPIModule.java b/android/src/main/java/com/iterable/reactnative/RNIterableAPIModule.java index 9b0bed33a..29a977068 100644 --- a/android/src/main/java/com/iterable/reactnative/RNIterableAPIModule.java +++ b/android/src/main/java/com/iterable/reactnative/RNIterableAPIModule.java @@ -482,6 +482,36 @@ public void updateVisibleRows(ReadableArray visibleRows) { // --------------------------------------------------------------------------------------- // endregion + // --------------------------------------------------------------------------------------- + // region Embedded APIs + + @ReactMethod + public void getEmbeddedPlacements(Promise promise) { + IterableLogger.d(TAG, "getEmbeddedPlacements"); + + JSONArray testPlacements = new JSONArray(); + int[] testPlacementIds = {808, 1121, 112}; + + try { + for (int placementId : testPlacementIds) { + testPlacements.put(createTestPlacement(placementId)); + } + + promise.resolve(Serialization.convertJsonToArray(testPlacements)); + } catch (JSONException e) { + promise.reject("", "Failed to create test placements"); + } + } + + private JSONObject createTestPlacement(int placementId) throws JSONException { + JSONObject placement = new JSONObject(); + placement.put("placementId", placementId); + return placement; + } + + // --------------------------------------------------------------------------------------- + // endregion + // --------------------------------------------------------------------------------------- // region Private Serialization Functions diff --git a/ios/RNIterableAPI/RNIterableAPI.m b/ios/RNIterableAPI/RNIterableAPI.m index 8850c755a..68c90b76c 100644 --- a/ios/RNIterableAPI/RNIterableAPI.m +++ b/ios/RNIterableAPI/RNIterableAPI.m @@ -133,6 +133,11 @@ @interface RCT_EXTERN_REMAP_MODULE(RNIterableAPI, ReactIterableAPI, NSObject) RCT_EXTERN_METHOD(updateVisibleRows: (nonnull NSArray *) visibleRows) +// MARK: - SDK Embedded Manager Functions + +RCT_EXTERN_METHOD(getEmbeddedPlacements: (RCTPromiseResolveBlock) resolve + rejecter: (RCTPromiseRejectBlock) reject) + // MARK: - SDK Auth Manager Functions RCT_EXTERN_METHOD(passAlongAuthToken: (NSString *) authToken) diff --git a/ios/RNIterableAPI/ReactIterableAPI.swift b/ios/RNIterableAPI/ReactIterableAPI.swift index 4db314f20..02b8fd2d9 100644 --- a/ios/RNIterableAPI/ReactIterableAPI.swift +++ b/ios/RNIterableAPI/ReactIterableAPI.swift @@ -470,6 +470,22 @@ class ReactIterableAPI: RCTEventEmitter { inboxSessionManager.updateVisibleRows(visibleRows: serializedRows) } + + // MARK: - SDK Embedded Manager Functions + + @objc(getEmbeddedPlacements:rejecter:) + func getEmbeddedPlacements(resolver: @escaping RCTPromiseResolveBlock, + rejecter: @escaping RCTPromiseRejectBlock) { + ITBInfo() + + // Create test data + let testPlacements: [[String: Any]] = [ + ["placementId": "meow"], + ["placementId": "woof woof"] + ] + + resolver(testPlacements) + } // MARK: - SDK Auth Manager Functions From 616503eed387767865968a8566e2534ad739cb72 Mon Sep 17 00:00:00 2001 From: Evan Greer Date: Wed, 4 Jun 2025 14:50:52 -0600 Subject: [PATCH 02/30] feat: adds base embedded files --- .../classes/IterableEmbeddedManager.ts | 24 +++++++++++++++++++ .../classes/IterableEmbeddedPlacement.ts | 11 +++++++++ src/embedded/classes/index.ts | 2 ++ src/embedded/index.ts | 1 + src/index.tsx | 4 ++++ 5 files changed, 42 insertions(+) create mode 100644 src/embedded/classes/IterableEmbeddedManager.ts create mode 100644 src/embedded/classes/IterableEmbeddedPlacement.ts create mode 100644 src/embedded/classes/index.ts create mode 100644 src/embedded/index.ts diff --git a/src/embedded/classes/IterableEmbeddedManager.ts b/src/embedded/classes/IterableEmbeddedManager.ts new file mode 100644 index 000000000..e570d7500 --- /dev/null +++ b/src/embedded/classes/IterableEmbeddedManager.ts @@ -0,0 +1,24 @@ +import { NativeModules } from 'react-native'; + +import { Iterable } from '../../core/classes/Iterable'; +import { IterableEmbeddedPlacement } from './IterableEmbeddedPlacement'; + +const RNIterableAPI = NativeModules.RNIterableAPI; + +/** + * Manages embedded messages for the current user. + * + * This class provides methods to interact with embedded messages, including retrieving placements. + */ +export class IterableEmbeddedManager { + /** + * Retrieve the current user's list of embedded placements. + * + * @returns A Promise that resolves to an array of embedded placements. + */ + getPlacements(): Promise { + Iterable?.logger?.log('EmbeddedManager.getPlacements'); + + return RNIterableAPI.getEmbeddedPlacements(); + } +} diff --git a/src/embedded/classes/IterableEmbeddedPlacement.ts b/src/embedded/classes/IterableEmbeddedPlacement.ts new file mode 100644 index 000000000..6a02aabfe --- /dev/null +++ b/src/embedded/classes/IterableEmbeddedPlacement.ts @@ -0,0 +1,11 @@ +/** + * Iterable embedded placement + * Contains placement id and the associated embedded messages + */ +export class IterableEmbeddedPlacement { + readonly placementId: number; + + constructor(placementId: number) { + this.placementId = placementId; + } +} diff --git a/src/embedded/classes/index.ts b/src/embedded/classes/index.ts new file mode 100644 index 000000000..9b605f651 --- /dev/null +++ b/src/embedded/classes/index.ts @@ -0,0 +1,2 @@ +export * from './IterableEmbeddedManager'; +export * from './IterableEmbeddedPlacement'; diff --git a/src/embedded/index.ts b/src/embedded/index.ts new file mode 100644 index 000000000..d7d17c691 --- /dev/null +++ b/src/embedded/index.ts @@ -0,0 +1 @@ +export * from './classes'; diff --git a/src/index.tsx b/src/index.tsx index 885cd74bd..8f13478c5 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -25,6 +25,10 @@ export { type IterableDeviceOrientation, } from './core/hooks'; export { type IterableEdgeInsetDetails } from './core/types'; +export { + IterableEmbeddedManager, + IterableEmbeddedPlacement, +} from './embedded/classes'; export { IterableHtmlInAppContent, IterableInAppCloseSource, From 75c7f1e166575e583eafd296b2b304c2c6038f9d Mon Sep 17 00:00:00 2001 From: Evan Greer Date: Wed, 4 Jun 2025 16:43:42 -0600 Subject: [PATCH 03/30] feat: adds enableEmbeddedMessaging flag to config object --- package.json | 2 +- src/core/classes/IterableConfig.ts | 8 ++++++++ src/itblBuildInfo.ts | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 2fde0d1e2..3701534b9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@iterable/react-native-sdk", - "version": "2.0.0", + "version": "2.0.0-rc.2", "description": "Iterable SDK for React Native.", "source": "./src/index.tsx", "main": "./lib/module/index.js", diff --git a/src/core/classes/IterableConfig.ts b/src/core/classes/IterableConfig.ts index 1c0550b0c..55539139c 100644 --- a/src/core/classes/IterableConfig.ts +++ b/src/core/classes/IterableConfig.ts @@ -294,6 +294,13 @@ export class IterableConfig { */ encryptionEnforced = false; + /** + * This specifies whether the SDK should enable embedded messaging. + * + * By default, the SDK will not enable embedded messaging. + */ + enableEmbeddedMessaging = false; + /** * Converts the IterableConfig instance to a dictionary object. * @@ -342,6 +349,7 @@ export class IterableConfig { dataRegion: this.dataRegion, pushPlatform: this.pushPlatform, encryptionEnforced: this.encryptionEnforced, + enableEmbeddedMessaging: this.enableEmbeddedMessaging, }; } } diff --git a/src/itblBuildInfo.ts b/src/itblBuildInfo.ts index 4cfc85365..a3a4ba80d 100644 --- a/src/itblBuildInfo.ts +++ b/src/itblBuildInfo.ts @@ -3,5 +3,5 @@ * It contains the version of the package */ export const buildInfo = { - version: '2.0.0', + version: '2.0.0-rc.2', }; From ca6911f788c3ba5bc5b991bb654879372a958c06 Mon Sep 17 00:00:00 2001 From: Evan Greer Date: Wed, 4 Jun 2025 17:14:04 -0600 Subject: [PATCH 04/30] feat: adds serialization of enableEmbeddedMessaging flag --- .../src/main/java/com/iterable/reactnative/Serialization.java | 4 ++++ package.json | 2 +- src/itblBuildInfo.ts | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/android/src/main/java/com/iterable/reactnative/Serialization.java b/android/src/main/java/com/iterable/reactnative/Serialization.java index 3a1f536a6..19b82182f 100644 --- a/android/src/main/java/com/iterable/reactnative/Serialization.java +++ b/android/src/main/java/com/iterable/reactnative/Serialization.java @@ -221,6 +221,10 @@ static IterableConfig.Builder getConfigFromReadableMap(ReadableMap iterableConte configBuilder.setEncryptionEnforced(iterableContextJSON.optBoolean("encryptionEnforced")); } + if (iterableContextJSON.has("enableEmbeddedMessaging")) { + configBuilder.setEnableEmbeddedMessaging(iterableContextJSON.optBoolean("enableEmbeddedMessaging")); + } + return configBuilder; } catch (JSONException e) { e.printStackTrace(); diff --git a/package.json b/package.json index 3701534b9..83919bf2f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@iterable/react-native-sdk", - "version": "2.0.0-rc.2", + "version": "2.0.0-rc.3", "description": "Iterable SDK for React Native.", "source": "./src/index.tsx", "main": "./lib/module/index.js", diff --git a/src/itblBuildInfo.ts b/src/itblBuildInfo.ts index a3a4ba80d..6d6fdacd3 100644 --- a/src/itblBuildInfo.ts +++ b/src/itblBuildInfo.ts @@ -3,5 +3,5 @@ * It contains the version of the package */ export const buildInfo = { - version: '2.0.0-rc.2', + version: '2.0.0-rc.3', }; From c8409f7a25864adc33252cdd048bcffe53cb6679 Mon Sep 17 00:00:00 2001 From: Evan Greer Date: Wed, 4 Jun 2025 17:17:17 -0600 Subject: [PATCH 05/30] chore: reverts version number --- package.json | 2 +- src/itblBuildInfo.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 83919bf2f..2fde0d1e2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@iterable/react-native-sdk", - "version": "2.0.0-rc.3", + "version": "2.0.0", "description": "Iterable SDK for React Native.", "source": "./src/index.tsx", "main": "./lib/module/index.js", diff --git a/src/itblBuildInfo.ts b/src/itblBuildInfo.ts index 6d6fdacd3..4cfc85365 100644 --- a/src/itblBuildInfo.ts +++ b/src/itblBuildInfo.ts @@ -3,5 +3,5 @@ * It contains the version of the package */ export const buildInfo = { - version: '2.0.0-rc.3', + version: '2.0.0', }; From a591d39a6189c068858424476e64c29e2486db77 Mon Sep 17 00:00:00 2001 From: Evan Greer Date: Fri, 6 Jun 2025 16:09:20 -0600 Subject: [PATCH 06/30] feat: test calling native method --- .../reactnative/RNIterableAPIModule.java | 20 ++++++------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/android/src/main/java/com/iterable/reactnative/RNIterableAPIModule.java b/android/src/main/java/com/iterable/reactnative/RNIterableAPIModule.java index 29a977068..d03050ba2 100644 --- a/android/src/main/java/com/iterable/reactnative/RNIterableAPIModule.java +++ b/android/src/main/java/com/iterable/reactnative/RNIterableAPIModule.java @@ -487,20 +487,12 @@ public void updateVisibleRows(ReadableArray visibleRows) { @ReactMethod public void getEmbeddedPlacements(Promise promise) { - IterableLogger.d(TAG, "getEmbeddedPlacements"); - - JSONArray testPlacements = new JSONArray(); - int[] testPlacementIds = {808, 1121, 112}; - - try { - for (int placementId : testPlacementIds) { - testPlacements.put(createTestPlacement(placementId)); - } - - promise.resolve(Serialization.convertJsonToArray(testPlacements)); - } catch (JSONException e) { - promise.reject("", "Failed to create test placements"); - } + + List messages = IterableApi.getInstance().getEmbeddedManager().getMessages(10); + IterableLogger.d(TAG, "Messages for placement: " + messages); + + // Return the collected logs as the success response + promise.resolve("success"); } private JSONObject createTestPlacement(int placementId) throws JSONException { From 5366d3a3acd5c37229c8e7e715ea03b584e5b0c4 Mon Sep 17 00:00:00 2001 From: Evan Greer Date: Fri, 6 Jun 2025 17:16:14 -0600 Subject: [PATCH 07/30] feat: adds serialization functions --- .../iterable/reactnative/RNIterableAPIModule.java | 12 ++++++------ .../java/com/iterable/reactnative/Serialization.java | 10 ++++++++++ package.json | 2 +- src/itblBuildInfo.ts | 2 +- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/android/src/main/java/com/iterable/reactnative/RNIterableAPIModule.java b/android/src/main/java/com/iterable/reactnative/RNIterableAPIModule.java index d03050ba2..77c2da175 100644 --- a/android/src/main/java/com/iterable/reactnative/RNIterableAPIModule.java +++ b/android/src/main/java/com/iterable/reactnative/RNIterableAPIModule.java @@ -486,13 +486,13 @@ public void updateVisibleRows(ReadableArray visibleRows) { // region Embedded APIs @ReactMethod - public void getEmbeddedPlacements(Promise promise) { - - List messages = IterableApi.getInstance().getEmbeddedManager().getMessages(10); - IterableLogger.d(TAG, "Messages for placement: " + messages); + public void getEmbeddedMessages(Promise promise) { + IterableLogger.d(TAG, "getEmbeddedMessages"); + + JSONArray embeddedMessageJsonArray = Serialization.serializeEmbeddedMessages(IterableApi.getInstance().getEmbeddedManager().getMessages(10)); + IterableLogger.d(TAG, "Messages for placement: " + embeddedMessageJsonArray); - // Return the collected logs as the success response - promise.resolve("success"); + promise.resolve("success"); } private JSONObject createTestPlacement(int placementId) throws JSONException { diff --git a/android/src/main/java/com/iterable/reactnative/Serialization.java b/android/src/main/java/com/iterable/reactnative/Serialization.java index 19b82182f..a74349c66 100644 --- a/android/src/main/java/com/iterable/reactnative/Serialization.java +++ b/android/src/main/java/com/iterable/reactnative/Serialization.java @@ -16,6 +16,7 @@ import com.iterable.iterableapi.IterableActionContext; import com.iterable.iterableapi.IterableConfig; import com.iterable.iterableapi.IterableDataRegion; +import com.iterable.iterableapi.IterableEmbeddedMessage; import com.iterable.iterableapi.IterableInAppCloseAction; import com.iterable.iterableapi.IterableInAppDeleteActionType; import com.iterable.iterableapi.IterableInAppHandler; @@ -136,6 +137,15 @@ static JSONArray serializeInAppMessages(List inAppMessages return inAppMessagesJson; } + static JSONArray serializeEmbeddedMessages(List embeddedMessages) { + JSONArray embeddedMessagesJson = new JSONArray(); + for (IterableEmbeddedMessage message : embeddedMessages) { + JSONObject messageJson = IterableEmbeddedMessage.Companion.toJSONObject(message); + embeddedMessagesJson.put(messageJson); + } + return embeddedMessagesJson; + } + static IterableConfig.Builder getConfigFromReadableMap(ReadableMap iterableContextMap) { try { JSONObject iterableContextJSON = convertMapToJson(iterableContextMap); diff --git a/package.json b/package.json index 2fde0d1e2..9d59b09bb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@iterable/react-native-sdk", - "version": "2.0.0", + "version": "2.0.0-rc.19", "description": "Iterable SDK for React Native.", "source": "./src/index.tsx", "main": "./lib/module/index.js", diff --git a/src/itblBuildInfo.ts b/src/itblBuildInfo.ts index 4cfc85365..4dcb9173b 100644 --- a/src/itblBuildInfo.ts +++ b/src/itblBuildInfo.ts @@ -3,5 +3,5 @@ * It contains the version of the package */ export const buildInfo = { - version: '2.0.0', + version: '2.0.0-rc.19', }; From aac04d5b0f99779ec15f3726c29779bc86256211 Mon Sep 17 00:00:00 2001 From: Evan Greer Date: Sat, 7 Jun 2025 08:07:23 -0600 Subject: [PATCH 08/30] chore: resets version number --- .../com/iterable/reactnative/RNIterableAPIModule.java | 11 ++++++++--- package.json | 2 +- src/itblBuildInfo.ts | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/android/src/main/java/com/iterable/reactnative/RNIterableAPIModule.java b/android/src/main/java/com/iterable/reactnative/RNIterableAPIModule.java index 77c2da175..1d27c107a 100644 --- a/android/src/main/java/com/iterable/reactnative/RNIterableAPIModule.java +++ b/android/src/main/java/com/iterable/reactnative/RNIterableAPIModule.java @@ -489,10 +489,15 @@ public void updateVisibleRows(ReadableArray visibleRows) { public void getEmbeddedMessages(Promise promise) { IterableLogger.d(TAG, "getEmbeddedMessages"); - JSONArray embeddedMessageJsonArray = Serialization.serializeEmbeddedMessages(IterableApi.getInstance().getEmbeddedManager().getMessages(10)); - IterableLogger.d(TAG, "Messages for placement: " + embeddedMessageJsonArray); + try { + JSONArray embeddedMessageJsonArray = Serialization.serializeEmbeddedMessages(IterableApi.getInstance().getEmbeddedManager().getMessages(10)); + IterableLogger.d(TAG, "Messages for placement: " + embeddedMessageJsonArray); - promise.resolve("success"); + promise.resolve("Success"); + } catch (JSONException e) { + IterableLogger.e(TAG, e.getLocalizedMessage()); + promise.reject("", "Failed to fetch messages with error " + e.getLocalizedMessage()); + } } private JSONObject createTestPlacement(int placementId) throws JSONException { diff --git a/package.json b/package.json index 9d59b09bb..2fde0d1e2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@iterable/react-native-sdk", - "version": "2.0.0-rc.19", + "version": "2.0.0", "description": "Iterable SDK for React Native.", "source": "./src/index.tsx", "main": "./lib/module/index.js", diff --git a/src/itblBuildInfo.ts b/src/itblBuildInfo.ts index 4dcb9173b..4cfc85365 100644 --- a/src/itblBuildInfo.ts +++ b/src/itblBuildInfo.ts @@ -3,5 +3,5 @@ * It contains the version of the package */ export const buildInfo = { - version: '2.0.0-rc.19', + version: '2.0.0', }; From 731609837c06a253cc31c96cbfff8c78ee6ef74d Mon Sep 17 00:00:00 2001 From: Evan Greer Date: Mon, 9 Jun 2025 09:44:54 -0600 Subject: [PATCH 09/30] feat: adds IterableEmbeddedMetadata class --- .../classes/IterableEmbeddedMetadata.ts | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 src/embedded/classes/IterableEmbeddedMetadata.ts diff --git a/src/embedded/classes/IterableEmbeddedMetadata.ts b/src/embedded/classes/IterableEmbeddedMetadata.ts new file mode 100644 index 000000000..02bc032d0 --- /dev/null +++ b/src/embedded/classes/IterableEmbeddedMetadata.ts @@ -0,0 +1,65 @@ +/** + * Metadata for an embedded message. + */ +export class IterableEmbeddedMessageMetadata { + /** The ID for the embedded message */ + readonly messageId: string; + /** The placement ID for the embedded message */ + readonly placementId: number; + /** The campaign ID for the embedded message */ + readonly campaignId?: number; + /** Whether the embedded message is a proof */ + readonly isProof: boolean; + + /** + * Constructs an instance of IterableEmbeddedMessageMetadata. + * + * @param messageId - The ID for the embedded message. + * @param placementId - The placement ID for the embedded message. + * @param campaignId - The campaign ID for the embedded message. + * @param isProof - Whether the embedded message is a proof. + */ + constructor( + messageId: string, + placementId: number, + campaignId: number | undefined, + isProof: boolean = false + ) { + this.messageId = messageId; + this.placementId = placementId; + this.campaignId = campaignId; + this.isProof = isProof; + } + + /** + * Creates an instance of `IterableEmbeddedMessageMetadata` from a dictionary object. + * + * @param dict - The dictionary objectcontaining the metadata properties. + * This corresponds to the properties in {@link IterableEmbeddedMessageMetadata} + * + * @returns A new instance of `IterableEmbeddedMessageMetadata` with the provided properties. + */ + static fromDict( + dict: Partial + ): IterableEmbeddedMessageMetadata { + if (!dict.messageId || !dict.placementId) { + throw new Error('messageId and placementId are required'); + } + return new IterableEmbeddedMessageMetadata( + dict.messageId, + dict.placementId, + dict.campaignId, + dict.isProof + ); + } +} + +/** + * An interface defining the dictionary object containing the metadata properties for an embedded message. + */ +export interface EmbeddedMessageMetadataDict { + messageId: string; + placementId: number; + campaignId?: number; + isProof?: boolean; +} From e121bc6823e5c349c8c00b525e88457cec0f80e4 Mon Sep 17 00:00:00 2001 From: Evan Greer Date: Mon, 9 Jun 2025 09:55:57 -0600 Subject: [PATCH 10/30] feat: adds unit tests --- .../IterableEmbeddedMessageMetadata.test.ts | 58 +++++++++++++++++++ ....ts => IterableEmbeddedMessageMetadata.ts} | 0 2 files changed, 58 insertions(+) create mode 100644 src/__tests__/IterableEmbeddedMessageMetadata.test.ts rename src/embedded/classes/{IterableEmbeddedMetadata.ts => IterableEmbeddedMessageMetadata.ts} (100%) diff --git a/src/__tests__/IterableEmbeddedMessageMetadata.test.ts b/src/__tests__/IterableEmbeddedMessageMetadata.test.ts new file mode 100644 index 000000000..f57786a9d --- /dev/null +++ b/src/__tests__/IterableEmbeddedMessageMetadata.test.ts @@ -0,0 +1,58 @@ +import { IterableEmbeddedMessageMetadata } from '../embedded/classes/IterableEmbeddedMessageMetadata'; +import { Iterable } from '../core'; + +describe('IterableEmbeddedMessage', () => { + test('should create an instance of IterableEmbeddedMessageMetadata from a dictionary', () => { + Iterable.logger.log( + 'iterableEmbeddedMessageMetadata_fromDict_valid_dictionary' + ); + + const dict = { + messageId: '123', + placementId: 456, + campaignId: 789, + isProof: false, + }; + + const result = IterableEmbeddedMessageMetadata.fromDict(dict); + + expect(result).toBeInstanceOf(IterableEmbeddedMessageMetadata); + expect(result.messageId).toBe('123'); + expect(result.placementId).toBe(456); + expect(result.campaignId).toBe(789); + expect(result.isProof).toBe(false); + }); + + test('should handle optional fields', () => { + Iterable.logger.log( + 'iterableEmbeddedMessageMetadata_fromDict_optional_fields_omitted' + ); + + const dict = { + messageId: '123', + placementId: 456, + }; + + const result = IterableEmbeddedMessageMetadata.fromDict(dict); + + expect(result).toBeInstanceOf(IterableEmbeddedMessageMetadata); + expect(result.messageId).toBe('123'); + expect(result.placementId).toBe(456); + expect(result.campaignId).toBeUndefined(); + expect(result.isProof).toBe(false); + }); + + test('should throw an error if messageId is not provided', () => { + Iterable.logger.log( + 'iterableEmbeddedMessageMetadata_fromDict_missing_messageId' + ); + + const dict = { + placementId: 456, + }; + + expect(() => { + IterableEmbeddedMessageMetadata.fromDict(dict); + }).toThrow('messageId and placementId are required'); + }); +}); diff --git a/src/embedded/classes/IterableEmbeddedMetadata.ts b/src/embedded/classes/IterableEmbeddedMessageMetadata.ts similarity index 100% rename from src/embedded/classes/IterableEmbeddedMetadata.ts rename to src/embedded/classes/IterableEmbeddedMessageMetadata.ts From 1c56ff1efa6db2b3635c1bec2a71ca1e9f05049a Mon Sep 17 00:00:00 2001 From: Evan Greer Date: Mon, 9 Jun 2025 11:30:49 -0600 Subject: [PATCH 11/30] feat: adds button class and associated classes --- .../IterableEmbeddedMessageElementsButton.ts | 61 +++++++++++++++++++ ...ableEmbeddedMessageElementsButtonAction.ts | 54 ++++++++++++++++ 2 files changed, 115 insertions(+) create mode 100644 src/embedded/classes/IterableEmbeddedMessageElementsButton.ts create mode 100644 src/embedded/classes/IterableEmbeddedMessageElementsButtonAction.ts diff --git a/src/embedded/classes/IterableEmbeddedMessageElementsButton.ts b/src/embedded/classes/IterableEmbeddedMessageElementsButton.ts new file mode 100644 index 000000000..b1481c9e6 --- /dev/null +++ b/src/embedded/classes/IterableEmbeddedMessageElementsButton.ts @@ -0,0 +1,61 @@ +import { IterableEmbeddedMessageElementsButtonAction } from './IterableEmbeddedMessageElementsButtonAction'; + +/** + * IterableEmbeddedMessageElementsButton represents a button in an embedded message. + */ +export class IterableEmbeddedMessageElementsButton { + /** The ID for the embedded message button */ + readonly id: string; + /** The title for the embedded message button */ + readonly title?: string; + /** The action for the embedded message button */ + readonly action?: IterableEmbeddedMessageElementsButtonAction; + + /** + * Creates an instance of IterableEmbeddedMessageButton. + * + * @param id - The ID for the embedded message button. + * @param title - The title for the embedded message button. + * @param action - The action for the embedded message button. + */ + constructor( + id: string, + title?: string, + action?: IterableEmbeddedMessageElementsButtonAction + ) { + this.id = id; + this.title = title; + this.action = action; + } + + /** + * Creates an instance of `IterableEmbeddedMessageButton` from a dictionary object. + * + * @param dict - The dictionary object containing the properties to initialize the `IterableEmbeddedMessageButton` instance. + * @returns A new instance of `IterableEmbeddedMessageButton` initialized with the provided dictionary properties. + */ + static fromDict( + dict: Partial + ): IterableEmbeddedMessageElementsButton { + if (!dict.id) { + throw new Error('id is required'); + } + const action = dict.action + ? IterableEmbeddedMessageElementsButtonAction.fromDict(dict.action) + : undefined; + return new IterableEmbeddedMessageElementsButton( + dict.id, + dict.title, + action + ); + } +} + +/** + * An interface defining the dictionary object containing the properties for the embedded message button. + */ +export interface EmbeddedMessageElementsButtonDict { + id: string; + title?: string; + action?: IterableEmbeddedMessageElementsButtonAction; +} diff --git a/src/embedded/classes/IterableEmbeddedMessageElementsButtonAction.ts b/src/embedded/classes/IterableEmbeddedMessageElementsButtonAction.ts new file mode 100644 index 000000000..c8dd24708 --- /dev/null +++ b/src/embedded/classes/IterableEmbeddedMessageElementsButtonAction.ts @@ -0,0 +1,54 @@ +/** + * IterableEmbeddedMessageElementsButtonAction represents an action defined as a response to user events + * for an embedded message button. + */ +export class IterableEmbeddedMessageElementsButtonAction { + /** + * The type of iterable action + * For custom actions, the type is `action://` prefix followed by a custom action name + */ + readonly type: string; + + /** + * The url for the action when the type is `openUrl` + * For custom actions, data is empty + */ + readonly data?: string; + + /** + * Creates an instance of IterableEmbeddedMessageElementsButtonAction. + * + * @param type - The type of the action. + * @param data - Optional data associated with the action. + */ + constructor(type: string, data?: string) { + this.type = type; + this.data = data; + } + + /** + * Creates an instance of `IterableEmbeddedMessageElementsButtonAction` from a dictionary object. + * + * @param dict - The dictionary object containing the properties to initialize the `IterableEmbeddedMessageElementsButtonAction` instance. + * @returns A new instance of `IterableEmbeddedMessageElementsButtonAction` initialized with the provided dictionary properties. + */ + static fromDict( + dict: Partial + ): IterableEmbeddedMessageElementsButtonAction { + if (!dict.type) { + throw new Error('type is required'); + } + return new IterableEmbeddedMessageElementsButtonAction( + dict.type, + dict.data + ); + } +} + +/** + * An interface defining the dictionary object containing the properties for the embedded message button action. + */ +export interface EmbeddedMessageButtonActionDict { + type: string; + data?: string; +} From 4578c011eccdb6b41e587dfaf28575ec8967dbfe Mon Sep 17 00:00:00 2001 From: Evan Greer Date: Mon, 9 Jun 2025 11:38:24 -0600 Subject: [PATCH 12/30] feat: adds unit tests --- ...rableEmbeddedMessageElementsButton.test.ts | 91 +++++++++++++++++++ ...mbeddedMessageElementsButtonAction.test.ts | 40 ++++++++ 2 files changed, 131 insertions(+) create mode 100644 src/__tests__/IterableEmbeddedMessageElementsButton.test.ts create mode 100644 src/__tests__/IterableEmbeddedMessageElementsButtonAction.test.ts diff --git a/src/__tests__/IterableEmbeddedMessageElementsButton.test.ts b/src/__tests__/IterableEmbeddedMessageElementsButton.test.ts new file mode 100644 index 000000000..1524d1c5b --- /dev/null +++ b/src/__tests__/IterableEmbeddedMessageElementsButton.test.ts @@ -0,0 +1,91 @@ +import { IterableEmbeddedMessageElementsButton } from '../embedded/classes/IterableEmbeddedMessageElementsButton'; +import { IterableEmbeddedMessageElementsButtonAction } from '../embedded/classes/IterableEmbeddedMessageElementsButtonAction'; +import { Iterable } from '../core/classes/Iterable'; + +describe('IterableEmbeddedMessageButton', () => { + it('should create an instance with all properties including button action', () => { + Iterable.logger.log( + 'iterableEmbeddedMessageButton_fromDict_all_properties' + ); + + const dict = { + id: 'button-123', + title: 'Click Me!', + action: { type: 'openUrl', data: 'https://example.com' }, + }; + + const button = IterableEmbeddedMessageElementsButton.fromDict(dict); + + expect(button).toBeInstanceOf(IterableEmbeddedMessageElementsButton); + expect(button.id).toBe('button-123'); + expect(button.title).toBe('Click Me!'); + expect(button.action).toBeInstanceOf( + IterableEmbeddedMessageElementsButtonAction + ); + expect(button.action?.type).toBe('openUrl'); + expect(button.action?.data).toBe('https://example.com'); + }); + + it('should create an instance with only required properties', () => { + Iterable.logger.log('iterableEmbeddedMessageButton_fromDict_required_only'); + + const dict = { id: 'button-123' }; + + const button = IterableEmbeddedMessageElementsButton.fromDict(dict); + + expect(button).toBeInstanceOf(IterableEmbeddedMessageElementsButton); + expect(button.id).toBe('button-123'); + expect(button.title).toBeUndefined(); + expect(button.action).toBeUndefined(); + }); + + it('should create an instance with title but no action', () => { + Iterable.logger.log('iterableEmbeddedMessageButton_fromDict_title_only'); + + const dict = { + id: 'button-123', + title: 'Click Me!', + }; + + const button = IterableEmbeddedMessageElementsButton.fromDict(dict); + + expect(button).toBeInstanceOf(IterableEmbeddedMessageElementsButton); + expect(button.id).toBe('button-123'); + expect(button.title).toBe('Click Me!'); + expect(button.action).toBeUndefined(); + }); + + it('should throw an error if id is missing in fromDict', () => { + Iterable.logger.log('iterableEmbeddedMessageButton_fromDict_missing_id'); + + const dict = { + title: 'Click Me!', + action: { type: 'openUrl', data: 'https://example.com' }, + }; + + expect(() => IterableEmbeddedMessageElementsButton.fromDict(dict)).toThrow( + 'id is required' + ); + }); + + it('should handle button action with only type', () => { + Iterable.logger.log( + 'iterableEmbeddedMessageButton_fromDict_action_type_only' + ); + + const dict = { + id: 'button-123', + action: { type: 'close' }, + }; + + const button = IterableEmbeddedMessageElementsButton.fromDict(dict); + + expect(button).toBeInstanceOf(IterableEmbeddedMessageElementsButton); + expect(button.id).toBe('button-123'); + expect(button.action).toBeInstanceOf( + IterableEmbeddedMessageElementsButtonAction + ); + expect(button.action?.type).toBe('close'); + expect(button.action?.data).toBeUndefined(); + }); +}); diff --git a/src/__tests__/IterableEmbeddedMessageElementsButtonAction.test.ts b/src/__tests__/IterableEmbeddedMessageElementsButtonAction.test.ts new file mode 100644 index 000000000..fa172cb7c --- /dev/null +++ b/src/__tests__/IterableEmbeddedMessageElementsButtonAction.test.ts @@ -0,0 +1,40 @@ +import { IterableEmbeddedMessageElementsButtonAction } from '../embedded/classes/IterableEmbeddedMessageElementsButtonAction'; +import { Iterable } from '../core/classes/Iterable'; + +describe('IterableEmbeddedMessageDefaultAction', () => { + it('should create an instance with the correct properties', () => { + Iterable.logger.log( + 'iterableEmbeddedMessageElementsButtonAction_fromDict_valid_dictionary' + ); + + const dict = { type: 'openUrl', data: 'https://example.com' }; + const action = IterableEmbeddedMessageElementsButtonAction.fromDict(dict); + expect(action).toBeInstanceOf(IterableEmbeddedMessageElementsButtonAction); + expect(action.type).toBe('openUrl'); + expect(action.data).toBe('https://example.com'); + }); + + it('should create an instance from a dictionary with data omitted', () => { + Iterable.logger.log( + 'iterableEmbeddedMessageElementsButtonAction_fromDict_valid_dictionary_with_data_omitted' + ); + + const dict = { type: 'action://join', data: '' }; + const action = IterableEmbeddedMessageElementsButtonAction.fromDict(dict); + expect(action).toBeInstanceOf(IterableEmbeddedMessageElementsButtonAction); + expect(action.type).toBe('action://join'); + expect(action.data).toBe(''); + }); + + it('should throw an error if type is missing in fromDict', () => { + Iterable.logger.log( + 'iterableEmbeddedMessageElementsButtonAction_fromDict_invalid_dictionary_missing_type' + ); + + const dict = { data: 'foo' }; + + expect(() => + IterableEmbeddedMessageElementsButtonAction.fromDict(dict) + ).toThrow('type is required'); + }); +}); From 57f48a3ff875fc8739d062a84180e5c64ad69a8f Mon Sep 17 00:00:00 2001 From: Evan Greer Date: Mon, 9 Jun 2025 12:11:02 -0600 Subject: [PATCH 13/30] feat: adds elements class and associated classes --- .../IterableEmbeddedMessageDefaultAction.ts | 51 +++++++++ .../IterableEmbeddedMessageElements.ts | 101 ++++++++++++++++++ ...ableEmbeddedMessageElementsButtonAction.ts | 4 +- .../classes/IterableEmbeddedMessageText.ts | 48 +++++++++ src/embedded/classes/index.ts | 3 + 5 files changed, 205 insertions(+), 2 deletions(-) create mode 100644 src/embedded/classes/IterableEmbeddedMessageDefaultAction.ts create mode 100644 src/embedded/classes/IterableEmbeddedMessageElements.ts create mode 100644 src/embedded/classes/IterableEmbeddedMessageText.ts diff --git a/src/embedded/classes/IterableEmbeddedMessageDefaultAction.ts b/src/embedded/classes/IterableEmbeddedMessageDefaultAction.ts new file mode 100644 index 000000000..01275c56d --- /dev/null +++ b/src/embedded/classes/IterableEmbeddedMessageDefaultAction.ts @@ -0,0 +1,51 @@ +/** + * IterableEmbeddedMessageDefaultAction represents the default action defined as + * a response to user events for an embedded message + */ +export class IterableEmbeddedMessageDefaultAction { + /** + * The type of iterable action + * For custom actions, the type is `action://` prefix followed by a custom action name + */ + readonly type: string; + + /** + * The url for the action when the type is `openUrl` + * For custom actions, data is empty + */ + readonly data?: string; + + /** + * Creates an instance of `IterableEmbeddedMessageDefaultAction`. + * + * @param type - The type of iterable action + * @param data - The url for the action when the type is `openUrl` + */ + constructor(type: string, data?: string) { + this.type = type; + this.data = data; + } + + /** + * Creates an instance of `IterableEmbeddedMessageDefaultAction` from a dictionary object. + * + * @param dict - The dictionary object containing the properties to initialize the `IterableEmbeddedMessageDefaultAction` instance. + * @returns A new instance of `IterableEmbeddedMessageDefaultAction` initialized with the provided dictionary properties. + */ + static fromDict( + dict: Partial + ): IterableEmbeddedMessageDefaultAction { + if (!dict.type) { + throw new Error('type is required'); + } + return new IterableEmbeddedMessageDefaultAction(dict.type, dict.data); + } +} + +/** + * An interface defining the dictionary object containing the properties for the embedded message default action. + */ +export interface EmbeddedMessageDefaultActionDict { + type: string; + data?: string; +} diff --git a/src/embedded/classes/IterableEmbeddedMessageElements.ts b/src/embedded/classes/IterableEmbeddedMessageElements.ts new file mode 100644 index 000000000..eeb8887c9 --- /dev/null +++ b/src/embedded/classes/IterableEmbeddedMessageElements.ts @@ -0,0 +1,101 @@ +import { IterableEmbeddedMessageDefaultAction } from './IterableEmbeddedMessageDefaultAction'; +import { IterableEmbeddedMessageElementsButton } from './IterableEmbeddedMessageElementsButton'; +import { IterableEmbeddedMessageText } from './IterableEmbeddedMessageText'; + +/** + * IterableEmbeddedMessageElements represents the elements of an embedded message. + */ +export class IterableEmbeddedMessageElements { + /** The title of the embedded message */ + readonly title?: string; + /** The body of the embedded message */ + readonly body?: string; + /** The url of the embedded message image */ + readonly mediaUrl?: string; + /** The caption of the embedded message image */ + readonly mediaUrlCaption?: string; + /** The default action of the embedded message */ + readonly defaultAction?: IterableEmbeddedMessageDefaultAction; + /** The buttons of the embedded message */ + readonly buttons?: IterableEmbeddedMessageElementsButton[]; + /** The text elements of the embedded message */ + readonly text?: IterableEmbeddedMessageText[]; + + /** + * Creates an instance of `IterableEmbeddedMessageElements`. + * + * @param title - The title of the embedded message. + * @param body - The body of the embedded message. + * @param mediaUrl - The url of the embedded message image. + * @param mediaUrlCaption - The caption of the embedded message image. + * @param defaultAction - The default action of the embedded message. + * @param buttons - The buttons of the embedded message. + * @param text - The text elements of the embedded message. + */ + constructor( + title?: string, + body?: string, + mediaUrl?: string, + mediaUrlCaption?: string, + defaultAction?: IterableEmbeddedMessageDefaultAction, + buttons?: IterableEmbeddedMessageElementsButton[], + text?: IterableEmbeddedMessageText[] + ) { + this.title = title; + this.body = body; + this.mediaUrl = mediaUrl; + this.mediaUrlCaption = mediaUrlCaption; + this.defaultAction = defaultAction; + this.buttons = buttons; + this.text = text; + } + + /** + * Creates an instance of `IterableEmbeddedMessageElements` from a dictionary object. + * + * @param dict - The dictionary object containing the properties to initialize the `IterableEmbeddedMessageElements` instance. + * @returns A new instance of `IterableEmbeddedMessageElements` initialized with the provided dictionary properties. + */ + static fromDict( + dict: Partial + ): IterableEmbeddedMessageElements { + const title = dict.title; + const body = dict.body; + const mediaUrl = dict.mediaUrl; + const mediaUrlCaption = dict.mediaUrlCaption; + const defaultAction = dict.defaultAction + ? IterableEmbeddedMessageDefaultAction.fromDict(dict.defaultAction) + : undefined; + + const buttons = dict.buttons?.map((button) => + IterableEmbeddedMessageElementsButton.fromDict(button) + ); + + const text = dict.text?.map((text) => + IterableEmbeddedMessageText.fromDict(text) + ); + + return new IterableEmbeddedMessageElements( + title, + body, + mediaUrl, + mediaUrlCaption, + defaultAction, + buttons, + text + ); + } +} + +/** + * An interface defining the dictionary object containing the properties for the embedded message elements. + */ +export interface EmbeddedMessageElementsDict { + title?: string; + body?: string; + mediaUrl?: string; + mediaUrlCaption?: string; + defaultAction?: IterableEmbeddedMessageDefaultAction; + buttons?: IterableEmbeddedMessageElementsButton[]; + text?: IterableEmbeddedMessageText[]; +} diff --git a/src/embedded/classes/IterableEmbeddedMessageElementsButtonAction.ts b/src/embedded/classes/IterableEmbeddedMessageElementsButtonAction.ts index c8dd24708..a924ffec5 100644 --- a/src/embedded/classes/IterableEmbeddedMessageElementsButtonAction.ts +++ b/src/embedded/classes/IterableEmbeddedMessageElementsButtonAction.ts @@ -1,6 +1,6 @@ /** - * IterableEmbeddedMessageElementsButtonAction represents an action defined as a response to user events - * for an embedded message button. + * IterableEmbeddedMessageElementsButtonAction represents an action defined as + * a response to user events for an embedded message button */ export class IterableEmbeddedMessageElementsButtonAction { /** diff --git a/src/embedded/classes/IterableEmbeddedMessageText.ts b/src/embedded/classes/IterableEmbeddedMessageText.ts new file mode 100644 index 000000000..d8a878519 --- /dev/null +++ b/src/embedded/classes/IterableEmbeddedMessageText.ts @@ -0,0 +1,48 @@ +/** + * IterableEmbeddedMessageText represents a text element in an embedded message. + */ +export class IterableEmbeddedMessageText { + /** The id of the text element */ + readonly id: string; + /** The text of the text element */ + readonly text?: string; + /** The type of the text element */ + readonly type?: string; + + /** + * Creates an instance of `IterableEmbeddedMessageText`. + * + * @param id - The id of the text element + * @param text - The text of the text element + * @param type - The type of the text element + */ + constructor(id: string, text?: string, type?: string) { + this.id = id; + this.text = text; + this.type = type; + } + + /** + * Creates an instance of `IterableEmbeddedMessageText` from a dictionary object. + * + * @param dict - The dictionary object containing the properties to initialize the `IterableEmbeddedMessageText` instance. + * @returns A new instance of `IterableEmbeddedMessageText` initialized with the provided dictionary properties. + */ + static fromDict( + dict: Partial + ): IterableEmbeddedMessageText { + if (!dict.id) { + throw new Error('id is required'); + } + return new IterableEmbeddedMessageText(dict.id, dict.text, dict.type); + } +} + +/** + * An interface defining the dictionary object containing the properties for an embedded message text. + */ +export interface EmbeddedMessageTextDict { + id: string; + text?: string; + type?: string; +} diff --git a/src/embedded/classes/index.ts b/src/embedded/classes/index.ts index 9b605f651..3b0ab3fa8 100644 --- a/src/embedded/classes/index.ts +++ b/src/embedded/classes/index.ts @@ -1,2 +1,5 @@ export * from './IterableEmbeddedManager'; export * from './IterableEmbeddedPlacement'; +export * from './IterableEmbeddedMessageElementsButton'; +export * from './IterableEmbeddedMessageElementsButtonAction'; +export * from './IterableEmbeddedMessageMetadata'; From a3397a4335f474f7c95ceb9ba3ddf7a2e40f2d96 Mon Sep 17 00:00:00 2001 From: Evan Greer Date: Mon, 9 Jun 2025 12:14:47 -0600 Subject: [PATCH 14/30] feat: adds unit tests --- ...erableEmbeddedMessageDefaultAction.test.ts | 40 ++++ .../IterableEmbeddedMessageElements.test.ts | 214 ++++++++++++++++++ .../IterableEmbeddedMessageText.test.ts | 38 ++++ 3 files changed, 292 insertions(+) create mode 100644 src/__tests__/IterableEmbeddedMessageDefaultAction.test.ts create mode 100644 src/__tests__/IterableEmbeddedMessageElements.test.ts create mode 100644 src/__tests__/IterableEmbeddedMessageText.test.ts diff --git a/src/__tests__/IterableEmbeddedMessageDefaultAction.test.ts b/src/__tests__/IterableEmbeddedMessageDefaultAction.test.ts new file mode 100644 index 000000000..bf99bc5b8 --- /dev/null +++ b/src/__tests__/IterableEmbeddedMessageDefaultAction.test.ts @@ -0,0 +1,40 @@ +import { IterableEmbeddedMessageDefaultAction } from '../embedded/classes/IterableEmbeddedMessageDefaultAction'; +import { Iterable } from '../core/classes/Iterable'; + +describe('IterableEmbeddedMessageDefaultAction', () => { + it('should create an instance with the correct properties', () => { + Iterable.logger.log( + 'iterableEmbeddedMessageDefaultAction_fromDict_valid_dictionary' + ); + + const dict = { type: 'openUrl', data: 'https://example.com' }; + const action = IterableEmbeddedMessageDefaultAction.fromDict(dict); + expect(action).toBeInstanceOf(IterableEmbeddedMessageDefaultAction); + expect(action.type).toBe('openUrl'); + expect(action.data).toBe('https://example.com'); + }); + + it('should create an instance from a dictionary with data omitted', () => { + Iterable.logger.log( + 'iterableEmbeddedMessageDefaultAction_fromDict_valid_dictionary_with_data_omitted' + ); + + const dict = { type: 'action://join', data: '' }; + const action = IterableEmbeddedMessageDefaultAction.fromDict(dict); + expect(action).toBeInstanceOf(IterableEmbeddedMessageDefaultAction); + expect(action.type).toBe('action://join'); + expect(action.data).toBe(''); + }); + + it('should throw an error if type is missing in fromDict', () => { + Iterable.logger.log( + 'iterableEmbeddedMessageDefaultAction_fromDict_invalid_dictionary_missing_type' + ); + + const dict = { data: 'foo' }; + + expect(() => IterableEmbeddedMessageDefaultAction.fromDict(dict)).toThrow( + 'type is required' + ); + }); +}); diff --git a/src/__tests__/IterableEmbeddedMessageElements.test.ts b/src/__tests__/IterableEmbeddedMessageElements.test.ts new file mode 100644 index 000000000..00028da5f --- /dev/null +++ b/src/__tests__/IterableEmbeddedMessageElements.test.ts @@ -0,0 +1,214 @@ +import { IterableEmbeddedMessageElements } from '../embedded/classes/IterableEmbeddedMessageElements'; +import { IterableEmbeddedMessageDefaultAction } from '../embedded/classes/IterableEmbeddedMessageDefaultAction'; +import { IterableEmbeddedMessageElementsButton } from '../embedded/classes/IterableEmbeddedMessageElementsButton'; +import { IterableEmbeddedMessageText } from '../embedded/classes/IterableEmbeddedMessageText'; +import { Iterable } from '../core/classes/Iterable'; + +describe('IterableEmbeddedMessageElements', () => { + it('should create an instance with all properties', () => { + Iterable.logger.log( + 'iterableEmbeddedMessageElements_fromDict_all_properties' + ); + + const dict = { + title: 'Awesome Title', + body: 'Radical Body Text', + mediaUrl: 'https://example.com/image.jpg', + mediaUrlCaption: 'Check out this sick image!', + defaultAction: { + type: 'openUrl', + data: 'https://example.com', + }, + buttons: [ + { + id: 'button-1', + title: 'Click Me!', + action: { + type: 'openUrl', + data: 'https://example.com/button1', + }, + }, + { + id: 'button-2', + title: 'Close', + action: { + type: 'action://dismiss', + }, + }, + ], + text: [ + { + id: 'text-1', + text: 'Some cool text', + type: 'body', + }, + { + id: 'text-2', + text: 'More radical text', + type: 'subtitle', + }, + ], + }; + + const elements = IterableEmbeddedMessageElements.fromDict(dict); + + expect(elements).toBeInstanceOf(IterableEmbeddedMessageElements); + expect(elements.title).toBe('Awesome Title'); + expect(elements.body).toBe('Radical Body Text'); + expect(elements.mediaUrl).toBe('https://example.com/image.jpg'); + expect(elements.mediaUrlCaption).toBe('Check out this sick image!'); + + // Check defaultAction + expect(elements.defaultAction).toBeInstanceOf( + IterableEmbeddedMessageDefaultAction + ); + expect(elements.defaultAction?.type).toBe('openUrl'); + expect(elements.defaultAction?.data).toBe('https://example.com'); + + // Check buttons + expect(elements.buttons).toHaveLength(2); + const firstButton = elements + .buttons![0] as IterableEmbeddedMessageElementsButton; + expect(firstButton).toBeInstanceOf(IterableEmbeddedMessageElementsButton); + expect(firstButton.id).toBe('button-1'); + expect(firstButton.title).toBe('Click Me!'); + expect(firstButton.action?.type).toBe('openUrl'); + expect(firstButton.action?.data).toBe('https://example.com/button1'); + + const secondButton = elements + .buttons![1] as IterableEmbeddedMessageElementsButton; + expect(secondButton).toBeInstanceOf(IterableEmbeddedMessageElementsButton); + expect(secondButton.id).toBe('button-2'); + expect(secondButton.title).toBe('Close'); + expect(secondButton.action?.type).toBe('action://dismiss'); + expect(secondButton.action?.data).toBeUndefined(); + + // Check text elements + expect(elements.text).toHaveLength(2); + const firstText = elements.text![0] as IterableEmbeddedMessageText; + expect(firstText).toBeInstanceOf(IterableEmbeddedMessageText); + expect(firstText.id).toBe('text-1'); + expect(firstText.text).toBe('Some cool text'); + expect(firstText.type).toBe('body'); + + const secondText = elements.text![1] as IterableEmbeddedMessageText; + expect(secondText).toBeInstanceOf(IterableEmbeddedMessageText); + expect(secondText.id).toBe('text-2'); + expect(secondText.text).toBe('More radical text'); + expect(secondText.type).toBe('subtitle'); + }); + + it('should create an instance with title and body', () => { + Iterable.logger.log( + 'iterableEmbeddedMessageElements_fromDict_title_and_body' + ); + + const dict = { + title: 'Simple Title', + body: 'Simple Body', + }; + + const elements = IterableEmbeddedMessageElements.fromDict(dict); + + expect(elements).toBeInstanceOf(IterableEmbeddedMessageElements); + expect(elements.title).toBe('Simple Title'); + expect(elements.body).toBe('Simple Body'); + expect(elements.mediaUrl).toBeUndefined(); + expect(elements.mediaUrlCaption).toBeUndefined(); + expect(elements.defaultAction).toBeUndefined(); + expect(elements.buttons).toBeUndefined(); + expect(elements.text).toBeUndefined(); + }); + + it('should create an instance with no title or body', () => { + Iterable.logger.log( + 'iterableEmbeddedMessageElements_fromDict_no_title_or_body' + ); + + const dict = {}; + + const elements = IterableEmbeddedMessageElements.fromDict(dict); + + expect(elements).toBeInstanceOf(IterableEmbeddedMessageElements); + expect(elements.title).toBeUndefined(); + expect(elements.body).toBeUndefined(); + expect(elements.mediaUrl).toBeUndefined(); + expect(elements.mediaUrlCaption).toBeUndefined(); + expect(elements.defaultAction).toBeUndefined(); + expect(elements.buttons).toBeUndefined(); + expect(elements.text).toBeUndefined(); + }); + + it('should create an instance with media properties', () => { + Iterable.logger.log( + 'iterableEmbeddedMessageElements_fromDict_media_properties' + ); + + const dict = { + title: 'Media Title', + body: 'Media Body', + mediaUrl: 'https://example.com/media.jpg', + mediaUrlCaption: 'Check this out!', + }; + + const elements = IterableEmbeddedMessageElements.fromDict(dict); + + expect(elements).toBeInstanceOf(IterableEmbeddedMessageElements); + expect(elements.title).toBe('Media Title'); + expect(elements.body).toBe('Media Body'); + expect(elements.mediaUrl).toBe('https://example.com/media.jpg'); + expect(elements.mediaUrlCaption).toBe('Check this out!'); + expect(elements.defaultAction).toBeUndefined(); + expect(elements.buttons).toBeUndefined(); + expect(elements.text).toBeUndefined(); + }); + + it('should create an instance with defaultAction only', () => { + Iterable.logger.log( + 'iterableEmbeddedMessageElements_fromDict_defaultAction_only' + ); + + const dict = { + title: 'Action Title', + body: 'Action Body', + defaultAction: { + type: 'openUrl', + data: 'https://example.com', + }, + }; + + const elements = IterableEmbeddedMessageElements.fromDict(dict); + + expect(elements).toBeInstanceOf(IterableEmbeddedMessageElements); + expect(elements.title).toBe('Action Title'); + expect(elements.body).toBe('Action Body'); + expect(elements.defaultAction).toBeInstanceOf( + IterableEmbeddedMessageDefaultAction + ); + expect(elements.defaultAction?.type).toBe('openUrl'); + expect(elements.defaultAction?.data).toBe('https://example.com'); + expect(elements.buttons).toBeUndefined(); + expect(elements.text).toBeUndefined(); + }); + + it('should create an instance with empty arrays for buttons and text', () => { + Iterable.logger.log( + 'iterableEmbeddedMessageElements_fromDict_empty_arrays' + ); + + const dict = { + title: 'Empty Arrays Title', + body: 'Empty Arrays Body', + buttons: [], + text: [], + }; + + const elements = IterableEmbeddedMessageElements.fromDict(dict); + + expect(elements).toBeInstanceOf(IterableEmbeddedMessageElements); + expect(elements.title).toBe('Empty Arrays Title'); + expect(elements.body).toBe('Empty Arrays Body'); + expect(elements.buttons).toHaveLength(0); + expect(elements.text).toHaveLength(0); + }); +}); diff --git a/src/__tests__/IterableEmbeddedMessageText.test.ts b/src/__tests__/IterableEmbeddedMessageText.test.ts new file mode 100644 index 000000000..10b3e2ffe --- /dev/null +++ b/src/__tests__/IterableEmbeddedMessageText.test.ts @@ -0,0 +1,38 @@ +import { IterableEmbeddedMessageText } from '../embedded/classes/IterableEmbeddedMessageText'; +import { Iterable } from '../core/classes/Iterable'; + +describe('IterableEmbeddedMessageText', () => { + it('should create an instance from a dictionary with all properties', () => { + Iterable.logger.log('iterableEmbeddedMessageText_fromDict_all_properties'); + + const dict = { id: 'text-123', text: 'Hello World!', type: 'heading' }; + const text = IterableEmbeddedMessageText.fromDict(dict); + + expect(text).toBeInstanceOf(IterableEmbeddedMessageText); + expect(text.id).toBe('text-123'); + expect(text.text).toBe('Hello World!'); + expect(text.type).toBe('heading'); + }); + + it('should create an instance from a dictionary with only required properties', () => { + Iterable.logger.log('iterableEmbeddedMessageText_fromDict_required_only'); + + const dict = { id: 'text-123' }; + const text = IterableEmbeddedMessageText.fromDict(dict); + + expect(text).toBeInstanceOf(IterableEmbeddedMessageText); + expect(text.id).toBe('text-123'); + expect(text.text).toBeUndefined(); + expect(text.type).toBeUndefined(); + }); + + it('should throw an error if id is missing in fromDict', () => { + Iterable.logger.log('iterableEmbeddedMessageText_fromDict_missing_id'); + + const dict = { text: 'Hello World!', type: 'heading' }; + + expect(() => IterableEmbeddedMessageText.fromDict(dict)).toThrow( + 'id is required' + ); + }); +}); From 79e72251b8016f48396eddaf205c1e2bcfed4b51 Mon Sep 17 00:00:00 2001 From: Evan Greer Date: Mon, 9 Jun 2025 12:48:23 -0600 Subject: [PATCH 15/30] feat: adds message class and unit tests --- src/__tests__/IterableEmbeddedMessage.test.ts | 163 ++++++++++++++++++ .../classes/IterableEmbeddedMessage.ts | 58 +++++++ 2 files changed, 221 insertions(+) create mode 100644 src/__tests__/IterableEmbeddedMessage.test.ts create mode 100644 src/embedded/classes/IterableEmbeddedMessage.ts diff --git a/src/__tests__/IterableEmbeddedMessage.test.ts b/src/__tests__/IterableEmbeddedMessage.test.ts new file mode 100644 index 000000000..64385e99f --- /dev/null +++ b/src/__tests__/IterableEmbeddedMessage.test.ts @@ -0,0 +1,163 @@ +import { IterableEmbeddedMessage } from '../embedded/classes/IterableEmbeddedMessage'; +import { IterableEmbeddedMessageMetadata } from '../embedded/classes/IterableEmbeddedMessageMetadata'; +import { IterableEmbeddedMessageElements } from '../embedded/classes/IterableEmbeddedMessageElements'; +import { Iterable } from '../core/classes/Iterable'; + +describe('IterableEmbeddedMessage', () => { + it('should create an instance with all properties', () => { + Iterable.logger.log('iterableEmbeddedMessage_fromDict_all_properties'); + + const dict = { + metadata: { + messageId: 'msg-123', + placementId: 1, + campaignId: 456, + isProof: false, + }, + elements: { + title: 'Awesome Title', + body: 'Radical Body Text', + mediaUrl: 'https://example.com/image.jpg', + mediaUrlCaption: 'Check out this sick image!', + defaultAction: { + type: 'openUrl', + data: 'https://example.com', + }, + buttons: [ + { + id: 'button-1', + title: 'Click Me!', + action: { + type: 'openUrl', + data: 'https://example.com/button1', + }, + }, + ], + text: [ + { + id: 'text-1', + text: 'Some cool text', + type: 'body', + }, + ], + }, + payload: { + customKey: 'customValue', + anotherKey: 123, + }, + }; + + const message = IterableEmbeddedMessage.fromDict(dict); + + expect(message).toBeInstanceOf(IterableEmbeddedMessage); + + // Check metadata + expect(message.metadata).toBeInstanceOf(IterableEmbeddedMessageMetadata); + expect(message.metadata.messageId).toBe('msg-123'); + expect(message.metadata.placementId).toBe(1); + expect(message.metadata.campaignId).toBe(456); + expect(message.metadata.isProof).toBe(false); + + // Check elements + expect(message.elements).toBeInstanceOf(IterableEmbeddedMessageElements); + expect(message.elements?.title).toBe('Awesome Title'); + expect(message.elements?.body).toBe('Radical Body Text'); + expect(message.elements?.mediaUrl).toBe('https://example.com/image.jpg'); + expect(message.elements?.mediaUrlCaption).toBe( + 'Check out this sick image!' + ); + + // Check payload + expect(message.payload).toEqual({ + customKey: 'customValue', + anotherKey: 123, + }); + }); + + it('should create an instance with only required metadata', () => { + Iterable.logger.log('iterableEmbeddedMessage_fromDict_required_only'); + + const dict = { + metadata: { + messageId: 'msg-123', + placementId: 1, + isProof: false, + }, + }; + + const message = IterableEmbeddedMessage.fromDict(dict); + + expect(message).toBeInstanceOf(IterableEmbeddedMessage); + expect(message.metadata).toBeInstanceOf(IterableEmbeddedMessageMetadata); + expect(message.metadata.messageId).toBe('msg-123'); + expect(message.metadata.placementId).toBe(1); + expect(message.metadata.campaignId).toBeUndefined(); + expect(message.metadata.isProof).toBe(false); + expect(message.elements).toBeUndefined(); + expect(message.payload).toBeUndefined(); + }); + + it('should throw an error if metadata is missing', () => { + Iterable.logger.log('iterableEmbeddedMessage_fromDict_missing_metadata'); + + const dict = { + elements: { + title: 'Some Title', + body: 'Some Body', + }, + }; + + expect(() => IterableEmbeddedMessage.fromDict(dict)).toThrow( + 'metadata is required' + ); + }); + + it('should create an instance with elements but no payload', () => { + Iterable.logger.log('iterableEmbeddedMessage_fromDict_elements_only'); + + const dict = { + metadata: { + messageId: 'msg-123', + placementId: 1, + isProof: false, + }, + elements: { + title: 'Elements Only', + body: 'No payload here', + }, + }; + + const message = IterableEmbeddedMessage.fromDict(dict); + + expect(message).toBeInstanceOf(IterableEmbeddedMessage); + expect(message.metadata).toBeInstanceOf(IterableEmbeddedMessageMetadata); + expect(message.elements).toBeInstanceOf(IterableEmbeddedMessageElements); + expect(message.elements?.title).toBe('Elements Only'); + expect(message.elements?.body).toBe('No payload here'); + expect(message.payload).toBeUndefined(); + }); + + it('should create an instance with payload but no elements', () => { + Iterable.logger.log('iterableEmbeddedMessage_fromDict_payload_only'); + + const dict = { + metadata: { + messageId: 'msg-123', + placementId: 1, + isProof: false, + }, + payload: { + someData: 'someValue', + }, + }; + + const message = IterableEmbeddedMessage.fromDict(dict); + + expect(message).toBeInstanceOf(IterableEmbeddedMessage); + expect(message.metadata).toBeInstanceOf(IterableEmbeddedMessageMetadata); + expect(message.elements).toBeUndefined(); + expect(message.payload).toEqual({ + someData: 'someValue', + }); + }); +}); diff --git a/src/embedded/classes/IterableEmbeddedMessage.ts b/src/embedded/classes/IterableEmbeddedMessage.ts new file mode 100644 index 000000000..47adb916a --- /dev/null +++ b/src/embedded/classes/IterableEmbeddedMessage.ts @@ -0,0 +1,58 @@ +import { IterableEmbeddedMessageMetadata } from './IterableEmbeddedMessageMetadata'; +import { IterableEmbeddedMessageElements } from './IterableEmbeddedMessageElements'; + +/** + * IterableEmbeddedMessage represents an embedded message. + */ +export class IterableEmbeddedMessage { + /** The metadata of the embedded message */ + metadata: IterableEmbeddedMessageMetadata; + /** The elements of the embedded message */ + elements?: IterableEmbeddedMessageElements; + /** The custom payload of the embedded message */ + payload?: Record; + + /** + * Creates an instance of `IterableEmbeddedMessage`. + * + * @param metadata - The metadata of the embedded message. + * @param elements - The elements of the embedded message. + * @param payload - The custom payload of the embedded message. + */ + constructor( + metadata: IterableEmbeddedMessageMetadata, + elements?: IterableEmbeddedMessageElements, + payload?: Record + ) { + this.metadata = metadata; + this.elements = elements; + this.payload = payload; + } + + /** + * Creates an instance of `IterableEmbeddedMessage` from a dictionary object. + * + * @param dict - The dictionary object containing the properties to initialize the `IterableEmbeddedMessage` instance. + * @returns A new instance of `IterableEmbeddedMessage` initialized with the provided dictionary properties. + */ + static fromDict(dict: Partial): IterableEmbeddedMessage { + if (!dict.metadata) { + throw new Error('metadata is required'); + } + const metadata = IterableEmbeddedMessageMetadata.fromDict(dict.metadata); + const elements = dict.elements + ? IterableEmbeddedMessageElements.fromDict(dict.elements) + : undefined; + const payload = dict.payload; + return new IterableEmbeddedMessage(metadata, elements, payload); + } +} + +/** + * An interface defining the dictionary object containing the properties for the embedded message. + */ +interface EmbeddedMessageDict { + metadata: IterableEmbeddedMessageMetadata; + elements: IterableEmbeddedMessageElements; + payload: Record; +} From 6f08aedd9bab208ed54bd6f273a0306f207c47ea Mon Sep 17 00:00:00 2001 From: Evan Greer Date: Mon, 9 Jun 2025 16:07:08 -0600 Subject: [PATCH 16/30] feat: adds enableEmbeddedMessaging to iOS config --- ios/RNIterableAPI/Serialization.swift | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ios/RNIterableAPI/Serialization.swift b/ios/RNIterableAPI/Serialization.swift index cb27026be..ea82bcf35 100644 --- a/ios/RNIterableAPI/Serialization.swift +++ b/ios/RNIterableAPI/Serialization.swift @@ -92,7 +92,10 @@ extension IterableConfig { config.dataRegion = IterableDataRegion.US } } - + + if let enableEmbeddedMessaging = dict["enableEmbeddedMesssaging"] as? Bool { + config.enableEmbeddedMessaging = enableEmbeddedMessaging + } return config } From 38eddb93ec314a772d69ca0728a9f68dfc402dab Mon Sep 17 00:00:00 2001 From: Evan Greer Date: Tue, 10 Jun 2025 14:17:24 -0600 Subject: [PATCH 17/30] feat: passes converted messages into promise --- .../com/iterable/reactnative/RNIterableAPIModule.java | 2 +- src/embedded/classes/IterableEmbeddedManager.ts | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/android/src/main/java/com/iterable/reactnative/RNIterableAPIModule.java b/android/src/main/java/com/iterable/reactnative/RNIterableAPIModule.java index 1d27c107a..ba4c565a9 100644 --- a/android/src/main/java/com/iterable/reactnative/RNIterableAPIModule.java +++ b/android/src/main/java/com/iterable/reactnative/RNIterableAPIModule.java @@ -493,7 +493,7 @@ public void getEmbeddedMessages(Promise promise) { JSONArray embeddedMessageJsonArray = Serialization.serializeEmbeddedMessages(IterableApi.getInstance().getEmbeddedManager().getMessages(10)); IterableLogger.d(TAG, "Messages for placement: " + embeddedMessageJsonArray); - promise.resolve("Success"); + promise.resolve(Serialization.convertJsonToArray(embeddedMessageJsonArray)); } catch (JSONException e) { IterableLogger.e(TAG, e.getLocalizedMessage()); promise.reject("", "Failed to fetch messages with error " + e.getLocalizedMessage()); diff --git a/src/embedded/classes/IterableEmbeddedManager.ts b/src/embedded/classes/IterableEmbeddedManager.ts index e570d7500..7bfae0c3a 100644 --- a/src/embedded/classes/IterableEmbeddedManager.ts +++ b/src/embedded/classes/IterableEmbeddedManager.ts @@ -1,7 +1,7 @@ import { NativeModules } from 'react-native'; import { Iterable } from '../../core/classes/Iterable'; -import { IterableEmbeddedPlacement } from './IterableEmbeddedPlacement'; +import type { IterableEmbeddedMessage } from './IterableEmbeddedMessage'; const RNIterableAPI = NativeModules.RNIterableAPI; @@ -16,9 +16,9 @@ export class IterableEmbeddedManager { * * @returns A Promise that resolves to an array of embedded placements. */ - getPlacements(): Promise { - Iterable?.logger?.log('EmbeddedManager.getPlacements'); + getMessages(): Promise { + Iterable?.logger?.log('EmbeddedManager.getMessages'); - return RNIterableAPI.getEmbeddedPlacements(); + return RNIterableAPI.getEmbeddedMessages(); } } From 6f1c83d5bb498a3cb1f3cb28dbd6506effc7fead Mon Sep 17 00:00:00 2001 From: Evan Greer Date: Fri, 13 Jun 2025 12:50:03 -0600 Subject: [PATCH 18/30] feat: adds placement id as a parameter to get embedded messages --- .../com/iterable/reactnative/RNIterableAPIModule.java | 6 +++--- src/embedded/classes/IterableEmbeddedManager.ts | 9 ++++++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/android/src/main/java/com/iterable/reactnative/RNIterableAPIModule.java b/android/src/main/java/com/iterable/reactnative/RNIterableAPIModule.java index ba4c565a9..cd46cc2ba 100644 --- a/android/src/main/java/com/iterable/reactnative/RNIterableAPIModule.java +++ b/android/src/main/java/com/iterable/reactnative/RNIterableAPIModule.java @@ -486,11 +486,11 @@ public void updateVisibleRows(ReadableArray visibleRows) { // region Embedded APIs @ReactMethod - public void getEmbeddedMessages(Promise promise) { - IterableLogger.d(TAG, "getEmbeddedMessages"); + public void getEmbeddedMessages(Integer placementId, Promise promise) { + IterableLogger.d(TAG, "getEmbeddedMessages for placement: " + placementId); try { - JSONArray embeddedMessageJsonArray = Serialization.serializeEmbeddedMessages(IterableApi.getInstance().getEmbeddedManager().getMessages(10)); + JSONArray embeddedMessageJsonArray = Serialization.serializeEmbeddedMessages(IterableApi.getInstance().getEmbeddedManager().getMessages(placementId)); IterableLogger.d(TAG, "Messages for placement: " + embeddedMessageJsonArray); promise.resolve(Serialization.convertJsonToArray(embeddedMessageJsonArray)); diff --git a/src/embedded/classes/IterableEmbeddedManager.ts b/src/embedded/classes/IterableEmbeddedManager.ts index 7bfae0c3a..a50235bf0 100644 --- a/src/embedded/classes/IterableEmbeddedManager.ts +++ b/src/embedded/classes/IterableEmbeddedManager.ts @@ -14,11 +14,14 @@ export class IterableEmbeddedManager { /** * Retrieve the current user's list of embedded placements. * + * @param {number} placementId The ID of the placement to retrieve messages from. * @returns A Promise that resolves to an array of embedded placements. */ - getMessages(): Promise { - Iterable?.logger?.log('EmbeddedManager.getMessages'); + getMessages(placementId: number): Promise { + Iterable?.logger?.log( + `EmbeddedManager.getMessages for placement ${placementId}` + ); - return RNIterableAPI.getEmbeddedMessages(); + return RNIterableAPI.getEmbeddedMessages(placementId); } } From c35774ba3d6d8344f66b84aecd1341ec152d0a28 Mon Sep 17 00:00:00 2001 From: Evan Greer Date: Tue, 17 Jun 2025 15:26:35 -0600 Subject: [PATCH 19/30] feat: adds null check --- .../main/java/com/iterable/reactnative/Serialization.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/android/src/main/java/com/iterable/reactnative/Serialization.java b/android/src/main/java/com/iterable/reactnative/Serialization.java index a74349c66..af33e2e1d 100644 --- a/android/src/main/java/com/iterable/reactnative/Serialization.java +++ b/android/src/main/java/com/iterable/reactnative/Serialization.java @@ -139,9 +139,11 @@ static JSONArray serializeInAppMessages(List inAppMessages static JSONArray serializeEmbeddedMessages(List embeddedMessages) { JSONArray embeddedMessagesJson = new JSONArray(); - for (IterableEmbeddedMessage message : embeddedMessages) { - JSONObject messageJson = IterableEmbeddedMessage.Companion.toJSONObject(message); - embeddedMessagesJson.put(messageJson); + if (embeddedMessages != null) { + for (IterableEmbeddedMessage message : embeddedMessages) { + JSONObject messageJson = IterableEmbeddedMessage.Companion.toJSONObject(message); + embeddedMessagesJson.put(messageJson); + } } return embeddedMessagesJson; } From 80d798144d85b1a70330e1d178d9362df0009e5b Mon Sep 17 00:00:00 2001 From: Evan Greer Date: Tue, 24 Jun 2025 13:27:26 -0600 Subject: [PATCH 20/30] feat: adds labels for dict --- src/embedded/classes/IterableEmbeddedMessageElementsButton.ts | 3 +++ .../classes/IterableEmbeddedMessageElementsButtonAction.ts | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/embedded/classes/IterableEmbeddedMessageElementsButton.ts b/src/embedded/classes/IterableEmbeddedMessageElementsButton.ts index b1481c9e6..64a516a20 100644 --- a/src/embedded/classes/IterableEmbeddedMessageElementsButton.ts +++ b/src/embedded/classes/IterableEmbeddedMessageElementsButton.ts @@ -55,7 +55,10 @@ export class IterableEmbeddedMessageElementsButton { * An interface defining the dictionary object containing the properties for the embedded message button. */ export interface EmbeddedMessageElementsButtonDict { + /** The ID for the embedded message button */ id: string; + /** The title for the embedded message button */ title?: string; + /** The action for the embedded message button */ action?: IterableEmbeddedMessageElementsButtonAction; } diff --git a/src/embedded/classes/IterableEmbeddedMessageElementsButtonAction.ts b/src/embedded/classes/IterableEmbeddedMessageElementsButtonAction.ts index c8dd24708..35283e010 100644 --- a/src/embedded/classes/IterableEmbeddedMessageElementsButtonAction.ts +++ b/src/embedded/classes/IterableEmbeddedMessageElementsButtonAction.ts @@ -49,6 +49,8 @@ export class IterableEmbeddedMessageElementsButtonAction { * An interface defining the dictionary object containing the properties for the embedded message button action. */ export interface EmbeddedMessageButtonActionDict { + /** The type of the action */ type: string; + /** The data associated with the action */ data?: string; } From 58fe64e25abd7d91d60562aadd74c03f7ab21532 Mon Sep 17 00:00:00 2001 From: Evan Greer Date: Tue, 24 Jun 2025 15:02:24 -0600 Subject: [PATCH 21/30] chore: adds comments to props --- .../classes/IterableEmbeddedMessageDefaultAction.ts | 2 ++ src/embedded/classes/IterableEmbeddedMessageElements.ts | 7 +++++++ src/embedded/classes/IterableEmbeddedMessageText.ts | 3 +++ 3 files changed, 12 insertions(+) diff --git a/src/embedded/classes/IterableEmbeddedMessageDefaultAction.ts b/src/embedded/classes/IterableEmbeddedMessageDefaultAction.ts index 01275c56d..06a36c00e 100644 --- a/src/embedded/classes/IterableEmbeddedMessageDefaultAction.ts +++ b/src/embedded/classes/IterableEmbeddedMessageDefaultAction.ts @@ -46,6 +46,8 @@ export class IterableEmbeddedMessageDefaultAction { * An interface defining the dictionary object containing the properties for the embedded message default action. */ export interface EmbeddedMessageDefaultActionDict { + /** The type of the action */ type: string; + /** The url for the action when the type is `openUrl` */ data?: string; } diff --git a/src/embedded/classes/IterableEmbeddedMessageElements.ts b/src/embedded/classes/IterableEmbeddedMessageElements.ts index eeb8887c9..73280b7e4 100644 --- a/src/embedded/classes/IterableEmbeddedMessageElements.ts +++ b/src/embedded/classes/IterableEmbeddedMessageElements.ts @@ -91,11 +91,18 @@ export class IterableEmbeddedMessageElements { * An interface defining the dictionary object containing the properties for the embedded message elements. */ export interface EmbeddedMessageElementsDict { + /** The title of the embedded message */ title?: string; + /** The body of the embedded message */ body?: string; + /** The url of the embedded message image */ mediaUrl?: string; + /** The caption of the embedded message image */ mediaUrlCaption?: string; + /** The default action of the embedded message */ defaultAction?: IterableEmbeddedMessageDefaultAction; + /** The buttons of the embedded message */ buttons?: IterableEmbeddedMessageElementsButton[]; + /** The text elements of the embedded message */ text?: IterableEmbeddedMessageText[]; } diff --git a/src/embedded/classes/IterableEmbeddedMessageText.ts b/src/embedded/classes/IterableEmbeddedMessageText.ts index d8a878519..06a553476 100644 --- a/src/embedded/classes/IterableEmbeddedMessageText.ts +++ b/src/embedded/classes/IterableEmbeddedMessageText.ts @@ -42,7 +42,10 @@ export class IterableEmbeddedMessageText { * An interface defining the dictionary object containing the properties for an embedded message text. */ export interface EmbeddedMessageTextDict { + /** The id of the text element */ id: string; + /** The text of the text element */ text?: string; + /** The type of the text element */ type?: string; } From 84e6a6883689666b2ab64babf9564c262467a17d Mon Sep 17 00:00:00 2001 From: Evan Greer Date: Tue, 24 Jun 2025 18:17:53 -0600 Subject: [PATCH 22/30] chore: adds comments to props --- src/embedded/classes/IterableEmbeddedMessage.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/embedded/classes/IterableEmbeddedMessage.ts b/src/embedded/classes/IterableEmbeddedMessage.ts index 47adb916a..c264bf262 100644 --- a/src/embedded/classes/IterableEmbeddedMessage.ts +++ b/src/embedded/classes/IterableEmbeddedMessage.ts @@ -52,7 +52,10 @@ export class IterableEmbeddedMessage { * An interface defining the dictionary object containing the properties for the embedded message. */ interface EmbeddedMessageDict { + /** The metadata of the embedded message */ metadata: IterableEmbeddedMessageMetadata; + /** The elements of the embedded message */ elements: IterableEmbeddedMessageElements; + /** The custom payload of the embedded message */ payload: Record; } From cad9c3ea46c3dab3764868bccbf0d410ac48beed Mon Sep 17 00:00:00 2001 From: Evan Greer Date: Thu, 26 Jun 2025 15:24:48 -0600 Subject: [PATCH 23/30] feat: merges action into button --- ...rableEmbeddedMessageElementsButton.test.ts | 23 +++----- ...mbeddedMessageElementsButtonAction.test.ts | 40 ------------- .../IterableEmbeddedMessageElements.ts | 4 +- .../IterableEmbeddedMessageElementsButton.ts | 52 +++++++---------- ...ableEmbeddedMessageElementsButtonAction.ts | 56 ------------------- src/embedded/classes/index.ts | 1 - 6 files changed, 30 insertions(+), 146 deletions(-) delete mode 100644 src/__tests__/IterableEmbeddedMessageElementsButtonAction.test.ts delete mode 100644 src/embedded/classes/IterableEmbeddedMessageElementsButtonAction.ts diff --git a/src/__tests__/IterableEmbeddedMessageElementsButton.test.ts b/src/__tests__/IterableEmbeddedMessageElementsButton.test.ts index 1524d1c5b..b9dcf1d7b 100644 --- a/src/__tests__/IterableEmbeddedMessageElementsButton.test.ts +++ b/src/__tests__/IterableEmbeddedMessageElementsButton.test.ts @@ -1,5 +1,4 @@ import { IterableEmbeddedMessageElementsButton } from '../embedded/classes/IterableEmbeddedMessageElementsButton'; -import { IterableEmbeddedMessageElementsButtonAction } from '../embedded/classes/IterableEmbeddedMessageElementsButtonAction'; import { Iterable } from '../core/classes/Iterable'; describe('IterableEmbeddedMessageButton', () => { @@ -14,14 +13,12 @@ describe('IterableEmbeddedMessageButton', () => { action: { type: 'openUrl', data: 'https://example.com' }, }; - const button = IterableEmbeddedMessageElementsButton.fromDict(dict); + const button = new IterableEmbeddedMessageElementsButton(dict); expect(button).toBeInstanceOf(IterableEmbeddedMessageElementsButton); expect(button.id).toBe('button-123'); expect(button.title).toBe('Click Me!'); - expect(button.action).toBeInstanceOf( - IterableEmbeddedMessageElementsButtonAction - ); + expect(button.action).toBeInstanceOf(Object); expect(button.action?.type).toBe('openUrl'); expect(button.action?.data).toBe('https://example.com'); }); @@ -31,7 +28,7 @@ describe('IterableEmbeddedMessageButton', () => { const dict = { id: 'button-123' }; - const button = IterableEmbeddedMessageElementsButton.fromDict(dict); + const button = new IterableEmbeddedMessageElementsButton(dict); expect(button).toBeInstanceOf(IterableEmbeddedMessageElementsButton); expect(button.id).toBe('button-123'); @@ -47,7 +44,7 @@ describe('IterableEmbeddedMessageButton', () => { title: 'Click Me!', }; - const button = IterableEmbeddedMessageElementsButton.fromDict(dict); + const button = new IterableEmbeddedMessageElementsButton(dict); expect(button).toBeInstanceOf(IterableEmbeddedMessageElementsButton); expect(button.id).toBe('button-123'); @@ -55,15 +52,15 @@ describe('IterableEmbeddedMessageButton', () => { expect(button.action).toBeUndefined(); }); - it('should throw an error if id is missing in fromDict', () => { + it('should throw an error if id is missing', () => { Iterable.logger.log('iterableEmbeddedMessageButton_fromDict_missing_id'); const dict = { title: 'Click Me!', action: { type: 'openUrl', data: 'https://example.com' }, }; - - expect(() => IterableEmbeddedMessageElementsButton.fromDict(dict)).toThrow( + // @ts-expect-error - id is purposely missing + expect(() => new IterableEmbeddedMessageElementsButton(dict)).toThrow( 'id is required' ); }); @@ -78,13 +75,11 @@ describe('IterableEmbeddedMessageButton', () => { action: { type: 'close' }, }; - const button = IterableEmbeddedMessageElementsButton.fromDict(dict); + const button = new IterableEmbeddedMessageElementsButton(dict); expect(button).toBeInstanceOf(IterableEmbeddedMessageElementsButton); expect(button.id).toBe('button-123'); - expect(button.action).toBeInstanceOf( - IterableEmbeddedMessageElementsButtonAction - ); + expect(button.action).toBeInstanceOf(Object); expect(button.action?.type).toBe('close'); expect(button.action?.data).toBeUndefined(); }); diff --git a/src/__tests__/IterableEmbeddedMessageElementsButtonAction.test.ts b/src/__tests__/IterableEmbeddedMessageElementsButtonAction.test.ts deleted file mode 100644 index fa172cb7c..000000000 --- a/src/__tests__/IterableEmbeddedMessageElementsButtonAction.test.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { IterableEmbeddedMessageElementsButtonAction } from '../embedded/classes/IterableEmbeddedMessageElementsButtonAction'; -import { Iterable } from '../core/classes/Iterable'; - -describe('IterableEmbeddedMessageDefaultAction', () => { - it('should create an instance with the correct properties', () => { - Iterable.logger.log( - 'iterableEmbeddedMessageElementsButtonAction_fromDict_valid_dictionary' - ); - - const dict = { type: 'openUrl', data: 'https://example.com' }; - const action = IterableEmbeddedMessageElementsButtonAction.fromDict(dict); - expect(action).toBeInstanceOf(IterableEmbeddedMessageElementsButtonAction); - expect(action.type).toBe('openUrl'); - expect(action.data).toBe('https://example.com'); - }); - - it('should create an instance from a dictionary with data omitted', () => { - Iterable.logger.log( - 'iterableEmbeddedMessageElementsButtonAction_fromDict_valid_dictionary_with_data_omitted' - ); - - const dict = { type: 'action://join', data: '' }; - const action = IterableEmbeddedMessageElementsButtonAction.fromDict(dict); - expect(action).toBeInstanceOf(IterableEmbeddedMessageElementsButtonAction); - expect(action.type).toBe('action://join'); - expect(action.data).toBe(''); - }); - - it('should throw an error if type is missing in fromDict', () => { - Iterable.logger.log( - 'iterableEmbeddedMessageElementsButtonAction_fromDict_invalid_dictionary_missing_type' - ); - - const dict = { data: 'foo' }; - - expect(() => - IterableEmbeddedMessageElementsButtonAction.fromDict(dict) - ).toThrow('type is required'); - }); -}); diff --git a/src/embedded/classes/IterableEmbeddedMessageElements.ts b/src/embedded/classes/IterableEmbeddedMessageElements.ts index 73280b7e4..04e2b3b38 100644 --- a/src/embedded/classes/IterableEmbeddedMessageElements.ts +++ b/src/embedded/classes/IterableEmbeddedMessageElements.ts @@ -67,8 +67,8 @@ export class IterableEmbeddedMessageElements { ? IterableEmbeddedMessageDefaultAction.fromDict(dict.defaultAction) : undefined; - const buttons = dict.buttons?.map((button) => - IterableEmbeddedMessageElementsButton.fromDict(button) + const buttons = dict.buttons?.map( + (button) => new IterableEmbeddedMessageElementsButton(button) ); const text = dict.text?.map((text) => diff --git a/src/embedded/classes/IterableEmbeddedMessageElementsButton.ts b/src/embedded/classes/IterableEmbeddedMessageElementsButton.ts index 64a516a20..7d41b50d8 100644 --- a/src/embedded/classes/IterableEmbeddedMessageElementsButton.ts +++ b/src/embedded/classes/IterableEmbeddedMessageElementsButton.ts @@ -1,5 +1,3 @@ -import { IterableEmbeddedMessageElementsButtonAction } from './IterableEmbeddedMessageElementsButtonAction'; - /** * IterableEmbeddedMessageElementsButton represents a button in an embedded message. */ @@ -9,45 +7,30 @@ export class IterableEmbeddedMessageElementsButton { /** The title for the embedded message button */ readonly title?: string; /** The action for the embedded message button */ - readonly action?: IterableEmbeddedMessageElementsButtonAction; + readonly action?: { + type: string; + data?: string; + }; /** * Creates an instance of IterableEmbeddedMessageButton. * - * @param id - The ID for the embedded message button. - * @param title - The title for the embedded message button. - * @param action - The action for the embedded message button. - */ - constructor( - id: string, - title?: string, - action?: IterableEmbeddedMessageElementsButtonAction - ) { - this.id = id; - this.title = title; - this.action = action; - } - - /** - * Creates an instance of `IterableEmbeddedMessageButton` from a dictionary object. - * * @param dict - The dictionary object containing the properties to initialize the `IterableEmbeddedMessageButton` instance. - * @returns A new instance of `IterableEmbeddedMessageButton` initialized with the provided dictionary properties. */ - static fromDict( - dict: Partial - ): IterableEmbeddedMessageElementsButton { + constructor(dict: EmbeddedMessageElementsButtonDict) { if (!dict.id) { throw new Error('id is required'); } - const action = dict.action - ? IterableEmbeddedMessageElementsButtonAction.fromDict(dict.action) - : undefined; - return new IterableEmbeddedMessageElementsButton( - dict.id, - dict.title, - action - ); + + this.id = dict.id; + this.title = dict.title; + + if (dict.action) { + this.action = { + type: dict.action.type, + data: dict.action.data, + }; + } } } @@ -60,5 +43,8 @@ export interface EmbeddedMessageElementsButtonDict { /** The title for the embedded message button */ title?: string; /** The action for the embedded message button */ - action?: IterableEmbeddedMessageElementsButtonAction; + action?: { + type: string; + data?: string; + }; } diff --git a/src/embedded/classes/IterableEmbeddedMessageElementsButtonAction.ts b/src/embedded/classes/IterableEmbeddedMessageElementsButtonAction.ts deleted file mode 100644 index 4061e2c6a..000000000 --- a/src/embedded/classes/IterableEmbeddedMessageElementsButtonAction.ts +++ /dev/null @@ -1,56 +0,0 @@ -/** - * IterableEmbeddedMessageElementsButtonAction represents an action defined as - * a response to user events for an embedded message button - */ -export class IterableEmbeddedMessageElementsButtonAction { - /** - * The type of iterable action - * For custom actions, the type is `action://` prefix followed by a custom action name - */ - readonly type: string; - - /** - * The url for the action when the type is `openUrl` - * For custom actions, data is empty - */ - readonly data?: string; - - /** - * Creates an instance of IterableEmbeddedMessageElementsButtonAction. - * - * @param type - The type of the action. - * @param data - Optional data associated with the action. - */ - constructor(type: string, data?: string) { - this.type = type; - this.data = data; - } - - /** - * Creates an instance of `IterableEmbeddedMessageElementsButtonAction` from a dictionary object. - * - * @param dict - The dictionary object containing the properties to initialize the `IterableEmbeddedMessageElementsButtonAction` instance. - * @returns A new instance of `IterableEmbeddedMessageElementsButtonAction` initialized with the provided dictionary properties. - */ - static fromDict( - dict: Partial - ): IterableEmbeddedMessageElementsButtonAction { - if (!dict.type) { - throw new Error('type is required'); - } - return new IterableEmbeddedMessageElementsButtonAction( - dict.type, - dict.data - ); - } -} - -/** - * An interface defining the dictionary object containing the properties for the embedded message button action. - */ -export interface EmbeddedMessageButtonActionDict { - /** The type of the action */ - type: string; - /** The data associated with the action */ - data?: string; -} diff --git a/src/embedded/classes/index.ts b/src/embedded/classes/index.ts index 3b0ab3fa8..5b943168e 100644 --- a/src/embedded/classes/index.ts +++ b/src/embedded/classes/index.ts @@ -1,5 +1,4 @@ export * from './IterableEmbeddedManager'; export * from './IterableEmbeddedPlacement'; export * from './IterableEmbeddedMessageElementsButton'; -export * from './IterableEmbeddedMessageElementsButtonAction'; export * from './IterableEmbeddedMessageMetadata'; From 5f51526a59da4e256c833916994d6cbddb889ca4 Mon Sep 17 00:00:00 2001 From: Evan Greer Date: Thu, 26 Jun 2025 15:54:16 -0600 Subject: [PATCH 24/30] feat: updates IterableEmbeddedMessageText class --- .../IterableEmbeddedMessageText.test.ts | 7 ++++--- .../IterableEmbeddedMessageElements.ts | 4 ++-- .../classes/IterableEmbeddedMessageText.ts | 21 +++++-------------- 3 files changed, 11 insertions(+), 21 deletions(-) diff --git a/src/__tests__/IterableEmbeddedMessageText.test.ts b/src/__tests__/IterableEmbeddedMessageText.test.ts index 10b3e2ffe..2ac677d55 100644 --- a/src/__tests__/IterableEmbeddedMessageText.test.ts +++ b/src/__tests__/IterableEmbeddedMessageText.test.ts @@ -6,7 +6,7 @@ describe('IterableEmbeddedMessageText', () => { Iterable.logger.log('iterableEmbeddedMessageText_fromDict_all_properties'); const dict = { id: 'text-123', text: 'Hello World!', type: 'heading' }; - const text = IterableEmbeddedMessageText.fromDict(dict); + const text = new IterableEmbeddedMessageText(dict); expect(text).toBeInstanceOf(IterableEmbeddedMessageText); expect(text.id).toBe('text-123'); @@ -18,7 +18,7 @@ describe('IterableEmbeddedMessageText', () => { Iterable.logger.log('iterableEmbeddedMessageText_fromDict_required_only'); const dict = { id: 'text-123' }; - const text = IterableEmbeddedMessageText.fromDict(dict); + const text = new IterableEmbeddedMessageText(dict); expect(text).toBeInstanceOf(IterableEmbeddedMessageText); expect(text.id).toBe('text-123'); @@ -31,7 +31,8 @@ describe('IterableEmbeddedMessageText', () => { const dict = { text: 'Hello World!', type: 'heading' }; - expect(() => IterableEmbeddedMessageText.fromDict(dict)).toThrow( + // @ts-expect-error - id is purposely missing + expect(() => new IterableEmbeddedMessageText(dict)).toThrow( 'id is required' ); }); diff --git a/src/embedded/classes/IterableEmbeddedMessageElements.ts b/src/embedded/classes/IterableEmbeddedMessageElements.ts index 04e2b3b38..740c0b143 100644 --- a/src/embedded/classes/IterableEmbeddedMessageElements.ts +++ b/src/embedded/classes/IterableEmbeddedMessageElements.ts @@ -71,8 +71,8 @@ export class IterableEmbeddedMessageElements { (button) => new IterableEmbeddedMessageElementsButton(button) ); - const text = dict.text?.map((text) => - IterableEmbeddedMessageText.fromDict(text) + const text = dict.text?.map( + (text) => new IterableEmbeddedMessageText(text) ); return new IterableEmbeddedMessageElements( diff --git a/src/embedded/classes/IterableEmbeddedMessageText.ts b/src/embedded/classes/IterableEmbeddedMessageText.ts index 06a553476..3b88dc8a8 100644 --- a/src/embedded/classes/IterableEmbeddedMessageText.ts +++ b/src/embedded/classes/IterableEmbeddedMessageText.ts @@ -16,25 +16,14 @@ export class IterableEmbeddedMessageText { * @param text - The text of the text element * @param type - The type of the text element */ - constructor(id: string, text?: string, type?: string) { - this.id = id; - this.text = text; - this.type = type; - } - - /** - * Creates an instance of `IterableEmbeddedMessageText` from a dictionary object. - * - * @param dict - The dictionary object containing the properties to initialize the `IterableEmbeddedMessageText` instance. - * @returns A new instance of `IterableEmbeddedMessageText` initialized with the provided dictionary properties. - */ - static fromDict( - dict: Partial - ): IterableEmbeddedMessageText { + constructor(dict: EmbeddedMessageTextDict) { if (!dict.id) { throw new Error('id is required'); } - return new IterableEmbeddedMessageText(dict.id, dict.text, dict.type); + + this.id = dict.id; + this.text = dict.text; + this.type = dict.type; } } From 7c2c8aa91ad515ea72324c9284a48c52b3452d91 Mon Sep 17 00:00:00 2001 From: Evan Greer Date: Thu, 26 Jun 2025 16:15:44 -0600 Subject: [PATCH 25/30] feat: converts IterableEmbeddedMessageElements constructor --- .../IterableEmbeddedMessageElements.test.ts | 12 ++-- .../classes/IterableEmbeddedMessage.ts | 2 +- .../IterableEmbeddedMessageElements.ts | 67 ++++--------------- 3 files changed, 20 insertions(+), 61 deletions(-) diff --git a/src/__tests__/IterableEmbeddedMessageElements.test.ts b/src/__tests__/IterableEmbeddedMessageElements.test.ts index 00028da5f..6887c44b6 100644 --- a/src/__tests__/IterableEmbeddedMessageElements.test.ts +++ b/src/__tests__/IterableEmbeddedMessageElements.test.ts @@ -50,7 +50,7 @@ describe('IterableEmbeddedMessageElements', () => { ], }; - const elements = IterableEmbeddedMessageElements.fromDict(dict); + const elements = new IterableEmbeddedMessageElements(dict); expect(elements).toBeInstanceOf(IterableEmbeddedMessageElements); expect(elements.title).toBe('Awesome Title'); @@ -108,7 +108,7 @@ describe('IterableEmbeddedMessageElements', () => { body: 'Simple Body', }; - const elements = IterableEmbeddedMessageElements.fromDict(dict); + const elements = new IterableEmbeddedMessageElements(dict); expect(elements).toBeInstanceOf(IterableEmbeddedMessageElements); expect(elements.title).toBe('Simple Title'); @@ -127,7 +127,7 @@ describe('IterableEmbeddedMessageElements', () => { const dict = {}; - const elements = IterableEmbeddedMessageElements.fromDict(dict); + const elements = new IterableEmbeddedMessageElements(dict); expect(elements).toBeInstanceOf(IterableEmbeddedMessageElements); expect(elements.title).toBeUndefined(); @@ -151,7 +151,7 @@ describe('IterableEmbeddedMessageElements', () => { mediaUrlCaption: 'Check this out!', }; - const elements = IterableEmbeddedMessageElements.fromDict(dict); + const elements = new IterableEmbeddedMessageElements(dict); expect(elements).toBeInstanceOf(IterableEmbeddedMessageElements); expect(elements.title).toBe('Media Title'); @@ -177,7 +177,7 @@ describe('IterableEmbeddedMessageElements', () => { }, }; - const elements = IterableEmbeddedMessageElements.fromDict(dict); + const elements = new IterableEmbeddedMessageElements(dict); expect(elements).toBeInstanceOf(IterableEmbeddedMessageElements); expect(elements.title).toBe('Action Title'); @@ -203,7 +203,7 @@ describe('IterableEmbeddedMessageElements', () => { text: [], }; - const elements = IterableEmbeddedMessageElements.fromDict(dict); + const elements = new IterableEmbeddedMessageElements(dict); expect(elements).toBeInstanceOf(IterableEmbeddedMessageElements); expect(elements.title).toBe('Empty Arrays Title'); diff --git a/src/embedded/classes/IterableEmbeddedMessage.ts b/src/embedded/classes/IterableEmbeddedMessage.ts index c264bf262..1ba7d330f 100644 --- a/src/embedded/classes/IterableEmbeddedMessage.ts +++ b/src/embedded/classes/IterableEmbeddedMessage.ts @@ -41,7 +41,7 @@ export class IterableEmbeddedMessage { } const metadata = IterableEmbeddedMessageMetadata.fromDict(dict.metadata); const elements = dict.elements - ? IterableEmbeddedMessageElements.fromDict(dict.elements) + ? new IterableEmbeddedMessageElements(dict.elements) : undefined; const payload = dict.payload; return new IterableEmbeddedMessage(metadata, elements, payload); diff --git a/src/embedded/classes/IterableEmbeddedMessageElements.ts b/src/embedded/classes/IterableEmbeddedMessageElements.ts index 740c0b143..d684a6816 100644 --- a/src/embedded/classes/IterableEmbeddedMessageElements.ts +++ b/src/embedded/classes/IterableEmbeddedMessageElements.ts @@ -2,6 +2,9 @@ import { IterableEmbeddedMessageDefaultAction } from './IterableEmbeddedMessageD import { IterableEmbeddedMessageElementsButton } from './IterableEmbeddedMessageElementsButton'; import { IterableEmbeddedMessageText } from './IterableEmbeddedMessageText'; +import type { EmbeddedMessageElementsButtonDict } from './IterableEmbeddedMessageElementsButton'; +import type { EmbeddedMessageTextDict } from './IterableEmbeddedMessageText'; + /** * IterableEmbeddedMessageElements represents the elements of an embedded message. */ @@ -24,66 +27,22 @@ export class IterableEmbeddedMessageElements { /** * Creates an instance of `IterableEmbeddedMessageElements`. * - * @param title - The title of the embedded message. - * @param body - The body of the embedded message. - * @param mediaUrl - The url of the embedded message image. - * @param mediaUrlCaption - The caption of the embedded message image. - * @param defaultAction - The default action of the embedded message. - * @param buttons - The buttons of the embedded message. - * @param text - The text elements of the embedded message. - */ - constructor( - title?: string, - body?: string, - mediaUrl?: string, - mediaUrlCaption?: string, - defaultAction?: IterableEmbeddedMessageDefaultAction, - buttons?: IterableEmbeddedMessageElementsButton[], - text?: IterableEmbeddedMessageText[] - ) { - this.title = title; - this.body = body; - this.mediaUrl = mediaUrl; - this.mediaUrlCaption = mediaUrlCaption; - this.defaultAction = defaultAction; - this.buttons = buttons; - this.text = text; - } - - /** - * Creates an instance of `IterableEmbeddedMessageElements` from a dictionary object. - * * @param dict - The dictionary object containing the properties to initialize the `IterableEmbeddedMessageElements` instance. - * @returns A new instance of `IterableEmbeddedMessageElements` initialized with the provided dictionary properties. */ - static fromDict( - dict: Partial - ): IterableEmbeddedMessageElements { - const title = dict.title; - const body = dict.body; - const mediaUrl = dict.mediaUrl; - const mediaUrlCaption = dict.mediaUrlCaption; - const defaultAction = dict.defaultAction + constructor(dict: Partial) { + this.title = dict.title; + this.body = dict.body; + this.mediaUrl = dict.mediaUrl; + this.mediaUrlCaption = dict.mediaUrlCaption; + this.defaultAction = dict.defaultAction ? IterableEmbeddedMessageDefaultAction.fromDict(dict.defaultAction) : undefined; - const buttons = dict.buttons?.map( + this.buttons = dict.buttons?.map( (button) => new IterableEmbeddedMessageElementsButton(button) ); - const text = dict.text?.map( - (text) => new IterableEmbeddedMessageText(text) - ); - - return new IterableEmbeddedMessageElements( - title, - body, - mediaUrl, - mediaUrlCaption, - defaultAction, - buttons, - text - ); + this.text = dict.text?.map((text) => new IterableEmbeddedMessageText(text)); } } @@ -102,7 +61,7 @@ export interface EmbeddedMessageElementsDict { /** The default action of the embedded message */ defaultAction?: IterableEmbeddedMessageDefaultAction; /** The buttons of the embedded message */ - buttons?: IterableEmbeddedMessageElementsButton[]; + buttons?: EmbeddedMessageElementsButtonDict[]; /** The text elements of the embedded message */ - text?: IterableEmbeddedMessageText[]; + text?: EmbeddedMessageTextDict[]; } From 3c0e01dea27117d2f82c8d311ea2e6a71ac1d168 Mon Sep 17 00:00:00 2001 From: Evan Greer Date: Thu, 26 Jun 2025 16:23:54 -0600 Subject: [PATCH 26/30] feat: removes default action class --- ...erableEmbeddedMessageDefaultAction.test.ts | 40 -------------- .../IterableEmbeddedMessageElements.test.ts | 9 +--- .../IterableEmbeddedMessageDefaultAction.ts | 53 ------------------- .../IterableEmbeddedMessageElements.ts | 21 +++++--- 4 files changed, 17 insertions(+), 106 deletions(-) delete mode 100644 src/__tests__/IterableEmbeddedMessageDefaultAction.test.ts delete mode 100644 src/embedded/classes/IterableEmbeddedMessageDefaultAction.ts diff --git a/src/__tests__/IterableEmbeddedMessageDefaultAction.test.ts b/src/__tests__/IterableEmbeddedMessageDefaultAction.test.ts deleted file mode 100644 index bf99bc5b8..000000000 --- a/src/__tests__/IterableEmbeddedMessageDefaultAction.test.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { IterableEmbeddedMessageDefaultAction } from '../embedded/classes/IterableEmbeddedMessageDefaultAction'; -import { Iterable } from '../core/classes/Iterable'; - -describe('IterableEmbeddedMessageDefaultAction', () => { - it('should create an instance with the correct properties', () => { - Iterable.logger.log( - 'iterableEmbeddedMessageDefaultAction_fromDict_valid_dictionary' - ); - - const dict = { type: 'openUrl', data: 'https://example.com' }; - const action = IterableEmbeddedMessageDefaultAction.fromDict(dict); - expect(action).toBeInstanceOf(IterableEmbeddedMessageDefaultAction); - expect(action.type).toBe('openUrl'); - expect(action.data).toBe('https://example.com'); - }); - - it('should create an instance from a dictionary with data omitted', () => { - Iterable.logger.log( - 'iterableEmbeddedMessageDefaultAction_fromDict_valid_dictionary_with_data_omitted' - ); - - const dict = { type: 'action://join', data: '' }; - const action = IterableEmbeddedMessageDefaultAction.fromDict(dict); - expect(action).toBeInstanceOf(IterableEmbeddedMessageDefaultAction); - expect(action.type).toBe('action://join'); - expect(action.data).toBe(''); - }); - - it('should throw an error if type is missing in fromDict', () => { - Iterable.logger.log( - 'iterableEmbeddedMessageDefaultAction_fromDict_invalid_dictionary_missing_type' - ); - - const dict = { data: 'foo' }; - - expect(() => IterableEmbeddedMessageDefaultAction.fromDict(dict)).toThrow( - 'type is required' - ); - }); -}); diff --git a/src/__tests__/IterableEmbeddedMessageElements.test.ts b/src/__tests__/IterableEmbeddedMessageElements.test.ts index 6887c44b6..64df9021a 100644 --- a/src/__tests__/IterableEmbeddedMessageElements.test.ts +++ b/src/__tests__/IterableEmbeddedMessageElements.test.ts @@ -1,5 +1,4 @@ import { IterableEmbeddedMessageElements } from '../embedded/classes/IterableEmbeddedMessageElements'; -import { IterableEmbeddedMessageDefaultAction } from '../embedded/classes/IterableEmbeddedMessageDefaultAction'; import { IterableEmbeddedMessageElementsButton } from '../embedded/classes/IterableEmbeddedMessageElementsButton'; import { IterableEmbeddedMessageText } from '../embedded/classes/IterableEmbeddedMessageText'; import { Iterable } from '../core/classes/Iterable'; @@ -59,9 +58,7 @@ describe('IterableEmbeddedMessageElements', () => { expect(elements.mediaUrlCaption).toBe('Check out this sick image!'); // Check defaultAction - expect(elements.defaultAction).toBeInstanceOf( - IterableEmbeddedMessageDefaultAction - ); + expect(elements.defaultAction).toBeInstanceOf(Object); expect(elements.defaultAction?.type).toBe('openUrl'); expect(elements.defaultAction?.data).toBe('https://example.com'); @@ -182,9 +179,7 @@ describe('IterableEmbeddedMessageElements', () => { expect(elements).toBeInstanceOf(IterableEmbeddedMessageElements); expect(elements.title).toBe('Action Title'); expect(elements.body).toBe('Action Body'); - expect(elements.defaultAction).toBeInstanceOf( - IterableEmbeddedMessageDefaultAction - ); + expect(elements.defaultAction).toBeInstanceOf(Object); expect(elements.defaultAction?.type).toBe('openUrl'); expect(elements.defaultAction?.data).toBe('https://example.com'); expect(elements.buttons).toBeUndefined(); diff --git a/src/embedded/classes/IterableEmbeddedMessageDefaultAction.ts b/src/embedded/classes/IterableEmbeddedMessageDefaultAction.ts deleted file mode 100644 index 06a36c00e..000000000 --- a/src/embedded/classes/IterableEmbeddedMessageDefaultAction.ts +++ /dev/null @@ -1,53 +0,0 @@ -/** - * IterableEmbeddedMessageDefaultAction represents the default action defined as - * a response to user events for an embedded message - */ -export class IterableEmbeddedMessageDefaultAction { - /** - * The type of iterable action - * For custom actions, the type is `action://` prefix followed by a custom action name - */ - readonly type: string; - - /** - * The url for the action when the type is `openUrl` - * For custom actions, data is empty - */ - readonly data?: string; - - /** - * Creates an instance of `IterableEmbeddedMessageDefaultAction`. - * - * @param type - The type of iterable action - * @param data - The url for the action when the type is `openUrl` - */ - constructor(type: string, data?: string) { - this.type = type; - this.data = data; - } - - /** - * Creates an instance of `IterableEmbeddedMessageDefaultAction` from a dictionary object. - * - * @param dict - The dictionary object containing the properties to initialize the `IterableEmbeddedMessageDefaultAction` instance. - * @returns A new instance of `IterableEmbeddedMessageDefaultAction` initialized with the provided dictionary properties. - */ - static fromDict( - dict: Partial - ): IterableEmbeddedMessageDefaultAction { - if (!dict.type) { - throw new Error('type is required'); - } - return new IterableEmbeddedMessageDefaultAction(dict.type, dict.data); - } -} - -/** - * An interface defining the dictionary object containing the properties for the embedded message default action. - */ -export interface EmbeddedMessageDefaultActionDict { - /** The type of the action */ - type: string; - /** The url for the action when the type is `openUrl` */ - data?: string; -} diff --git a/src/embedded/classes/IterableEmbeddedMessageElements.ts b/src/embedded/classes/IterableEmbeddedMessageElements.ts index d684a6816..b5dc63b6a 100644 --- a/src/embedded/classes/IterableEmbeddedMessageElements.ts +++ b/src/embedded/classes/IterableEmbeddedMessageElements.ts @@ -1,4 +1,3 @@ -import { IterableEmbeddedMessageDefaultAction } from './IterableEmbeddedMessageDefaultAction'; import { IterableEmbeddedMessageElementsButton } from './IterableEmbeddedMessageElementsButton'; import { IterableEmbeddedMessageText } from './IterableEmbeddedMessageText'; @@ -18,7 +17,10 @@ export class IterableEmbeddedMessageElements { /** The caption of the embedded message image */ readonly mediaUrlCaption?: string; /** The default action of the embedded message */ - readonly defaultAction?: IterableEmbeddedMessageDefaultAction; + readonly defaultAction?: { + type: string; + data?: string; + }; /** The buttons of the embedded message */ readonly buttons?: IterableEmbeddedMessageElementsButton[]; /** The text elements of the embedded message */ @@ -34,9 +36,13 @@ export class IterableEmbeddedMessageElements { this.body = dict.body; this.mediaUrl = dict.mediaUrl; this.mediaUrlCaption = dict.mediaUrlCaption; - this.defaultAction = dict.defaultAction - ? IterableEmbeddedMessageDefaultAction.fromDict(dict.defaultAction) - : undefined; + + if (dict.defaultAction) { + this.defaultAction = { + type: dict.defaultAction.type, + data: dict.defaultAction.data, + }; + } this.buttons = dict.buttons?.map( (button) => new IterableEmbeddedMessageElementsButton(button) @@ -59,7 +65,10 @@ export interface EmbeddedMessageElementsDict { /** The caption of the embedded message image */ mediaUrlCaption?: string; /** The default action of the embedded message */ - defaultAction?: IterableEmbeddedMessageDefaultAction; + defaultAction?: { + type: string; + data?: string; + }; /** The buttons of the embedded message */ buttons?: EmbeddedMessageElementsButtonDict[]; /** The text elements of the embedded message */ From 56b33b02304cfca8858a1e02912dfab7679bdda1 Mon Sep 17 00:00:00 2001 From: Evan Greer Date: Thu, 26 Jun 2025 16:45:32 -0600 Subject: [PATCH 27/30] feat: converts IterableEmbeddedMessage constructor --- src/__tests__/IterableEmbeddedMessage.test.ts | 13 +++-- .../IterableEmbeddedMessageMetadata.test.ts | 7 ++- .../classes/IterableEmbeddedMessage.ts | 58 +++++++++---------- .../IterableEmbeddedMessageMetadata.ts | 39 ++----------- 4 files changed, 44 insertions(+), 73 deletions(-) diff --git a/src/__tests__/IterableEmbeddedMessage.test.ts b/src/__tests__/IterableEmbeddedMessage.test.ts index 64385e99f..79c6d660b 100644 --- a/src/__tests__/IterableEmbeddedMessage.test.ts +++ b/src/__tests__/IterableEmbeddedMessage.test.ts @@ -47,12 +47,12 @@ describe('IterableEmbeddedMessage', () => { }, }; - const message = IterableEmbeddedMessage.fromDict(dict); + const message = new IterableEmbeddedMessage(dict); expect(message).toBeInstanceOf(IterableEmbeddedMessage); // Check metadata - expect(message.metadata).toBeInstanceOf(IterableEmbeddedMessageMetadata); + expect(message.metadata).toBeInstanceOf(Object); expect(message.metadata.messageId).toBe('msg-123'); expect(message.metadata.placementId).toBe(1); expect(message.metadata.campaignId).toBe(456); @@ -85,7 +85,7 @@ describe('IterableEmbeddedMessage', () => { }, }; - const message = IterableEmbeddedMessage.fromDict(dict); + const message = new IterableEmbeddedMessage(dict); expect(message).toBeInstanceOf(IterableEmbeddedMessage); expect(message.metadata).toBeInstanceOf(IterableEmbeddedMessageMetadata); @@ -107,7 +107,8 @@ describe('IterableEmbeddedMessage', () => { }, }; - expect(() => IterableEmbeddedMessage.fromDict(dict)).toThrow( + // @ts-expect-error - metadata is purposely missing + expect(() => new IterableEmbeddedMessage(dict)).toThrow( 'metadata is required' ); }); @@ -127,7 +128,7 @@ describe('IterableEmbeddedMessage', () => { }, }; - const message = IterableEmbeddedMessage.fromDict(dict); + const message = new IterableEmbeddedMessage(dict); expect(message).toBeInstanceOf(IterableEmbeddedMessage); expect(message.metadata).toBeInstanceOf(IterableEmbeddedMessageMetadata); @@ -151,7 +152,7 @@ describe('IterableEmbeddedMessage', () => { }, }; - const message = IterableEmbeddedMessage.fromDict(dict); + const message = new IterableEmbeddedMessage(dict); expect(message).toBeInstanceOf(IterableEmbeddedMessage); expect(message.metadata).toBeInstanceOf(IterableEmbeddedMessageMetadata); diff --git a/src/__tests__/IterableEmbeddedMessageMetadata.test.ts b/src/__tests__/IterableEmbeddedMessageMetadata.test.ts index f57786a9d..8f03a5287 100644 --- a/src/__tests__/IterableEmbeddedMessageMetadata.test.ts +++ b/src/__tests__/IterableEmbeddedMessageMetadata.test.ts @@ -14,7 +14,7 @@ describe('IterableEmbeddedMessage', () => { isProof: false, }; - const result = IterableEmbeddedMessageMetadata.fromDict(dict); + const result = new IterableEmbeddedMessageMetadata(dict); expect(result).toBeInstanceOf(IterableEmbeddedMessageMetadata); expect(result.messageId).toBe('123'); @@ -33,7 +33,7 @@ describe('IterableEmbeddedMessage', () => { placementId: 456, }; - const result = IterableEmbeddedMessageMetadata.fromDict(dict); + const result = new IterableEmbeddedMessageMetadata(dict); expect(result).toBeInstanceOf(IterableEmbeddedMessageMetadata); expect(result.messageId).toBe('123'); @@ -52,7 +52,8 @@ describe('IterableEmbeddedMessage', () => { }; expect(() => { - IterableEmbeddedMessageMetadata.fromDict(dict); + // @ts-expect-error - messageId is purposely missing + new IterableEmbeddedMessageMetadata(dict); }).toThrow('messageId and placementId are required'); }); }); diff --git a/src/embedded/classes/IterableEmbeddedMessage.ts b/src/embedded/classes/IterableEmbeddedMessage.ts index 1ba7d330f..c3fbe9607 100644 --- a/src/embedded/classes/IterableEmbeddedMessage.ts +++ b/src/embedded/classes/IterableEmbeddedMessage.ts @@ -1,61 +1,57 @@ -import { IterableEmbeddedMessageMetadata } from './IterableEmbeddedMessageMetadata'; import { IterableEmbeddedMessageElements } from './IterableEmbeddedMessageElements'; +import type { EmbeddedMessageElementsDict } from './IterableEmbeddedMessageElements'; /** * IterableEmbeddedMessage represents an embedded message. */ export class IterableEmbeddedMessage { /** The metadata of the embedded message */ - metadata: IterableEmbeddedMessageMetadata; + readonly metadata: { + messageId: string; + placementId: number; + campaignId?: number; + isProof: boolean; + }; /** The elements of the embedded message */ - elements?: IterableEmbeddedMessageElements; + readonly elements?: IterableEmbeddedMessageElements; /** The custom payload of the embedded message */ - payload?: Record; + readonly payload?: Record; /** * Creates an instance of `IterableEmbeddedMessage`. * - * @param metadata - The metadata of the embedded message. - * @param elements - The elements of the embedded message. - * @param payload - The custom payload of the embedded message. - */ - constructor( - metadata: IterableEmbeddedMessageMetadata, - elements?: IterableEmbeddedMessageElements, - payload?: Record - ) { - this.metadata = metadata; - this.elements = elements; - this.payload = payload; - } - - /** - * Creates an instance of `IterableEmbeddedMessage` from a dictionary object. - * * @param dict - The dictionary object containing the properties to initialize the `IterableEmbeddedMessage` instance. - * @returns A new instance of `IterableEmbeddedMessage` initialized with the provided dictionary properties. */ - static fromDict(dict: Partial): IterableEmbeddedMessage { + constructor(dict: EmbeddedMessageDict) { if (!dict.metadata) { throw new Error('metadata is required'); } - const metadata = IterableEmbeddedMessageMetadata.fromDict(dict.metadata); - const elements = dict.elements + this.metadata = { + messageId: dict.metadata.messageId, + placementId: dict.metadata.placementId, + campaignId: dict.metadata.campaignId, + isProof: dict.metadata.isProof, + }; + this.elements = dict.elements ? new IterableEmbeddedMessageElements(dict.elements) : undefined; - const payload = dict.payload; - return new IterableEmbeddedMessage(metadata, elements, payload); + this.payload = dict.payload; } } /** * An interface defining the dictionary object containing the properties for the embedded message. */ -interface EmbeddedMessageDict { +export interface EmbeddedMessageDict { /** The metadata of the embedded message */ - metadata: IterableEmbeddedMessageMetadata; + metadata: { + messageId: string; + placementId: number; + campaignId?: number; + isProof: boolean; + }; /** The elements of the embedded message */ - elements: IterableEmbeddedMessageElements; + elements?: EmbeddedMessageElementsDict; /** The custom payload of the embedded message */ - payload: Record; + payload?: Record; } diff --git a/src/embedded/classes/IterableEmbeddedMessageMetadata.ts b/src/embedded/classes/IterableEmbeddedMessageMetadata.ts index 02bc032d0..8be0cfa5c 100644 --- a/src/embedded/classes/IterableEmbeddedMessageMetadata.ts +++ b/src/embedded/classes/IterableEmbeddedMessageMetadata.ts @@ -14,43 +14,16 @@ export class IterableEmbeddedMessageMetadata { /** * Constructs an instance of IterableEmbeddedMessageMetadata. * - * @param messageId - The ID for the embedded message. - * @param placementId - The placement ID for the embedded message. - * @param campaignId - The campaign ID for the embedded message. - * @param isProof - Whether the embedded message is a proof. + * @param dict - The dictionary object containing the metadata properties. */ - constructor( - messageId: string, - placementId: number, - campaignId: number | undefined, - isProof: boolean = false - ) { - this.messageId = messageId; - this.placementId = placementId; - this.campaignId = campaignId; - this.isProof = isProof; - } - - /** - * Creates an instance of `IterableEmbeddedMessageMetadata` from a dictionary object. - * - * @param dict - The dictionary objectcontaining the metadata properties. - * This corresponds to the properties in {@link IterableEmbeddedMessageMetadata} - * - * @returns A new instance of `IterableEmbeddedMessageMetadata` with the provided properties. - */ - static fromDict( - dict: Partial - ): IterableEmbeddedMessageMetadata { + constructor(dict: EmbeddedMessageMetadataDict) { if (!dict.messageId || !dict.placementId) { throw new Error('messageId and placementId are required'); } - return new IterableEmbeddedMessageMetadata( - dict.messageId, - dict.placementId, - dict.campaignId, - dict.isProof - ); + this.messageId = dict.messageId; + this.placementId = dict.placementId; + this.campaignId = dict.campaignId; + this.isProof = dict.isProof ?? false; } } From 1db3333ab74d5cd930cd96fa43ad8ece5eaad3b2 Mon Sep 17 00:00:00 2001 From: Evan Greer Date: Thu, 26 Jun 2025 16:48:02 -0600 Subject: [PATCH 28/30] feat: converts IterableEmbeddedMessage constructor --- src/__tests__/IterableEmbeddedMessage.test.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/__tests__/IterableEmbeddedMessage.test.ts b/src/__tests__/IterableEmbeddedMessage.test.ts index 79c6d660b..fdcb145ef 100644 --- a/src/__tests__/IterableEmbeddedMessage.test.ts +++ b/src/__tests__/IterableEmbeddedMessage.test.ts @@ -1,5 +1,4 @@ import { IterableEmbeddedMessage } from '../embedded/classes/IterableEmbeddedMessage'; -import { IterableEmbeddedMessageMetadata } from '../embedded/classes/IterableEmbeddedMessageMetadata'; import { IterableEmbeddedMessageElements } from '../embedded/classes/IterableEmbeddedMessageElements'; import { Iterable } from '../core/classes/Iterable'; @@ -88,7 +87,7 @@ describe('IterableEmbeddedMessage', () => { const message = new IterableEmbeddedMessage(dict); expect(message).toBeInstanceOf(IterableEmbeddedMessage); - expect(message.metadata).toBeInstanceOf(IterableEmbeddedMessageMetadata); + expect(message.metadata).toBeInstanceOf(Object); expect(message.metadata.messageId).toBe('msg-123'); expect(message.metadata.placementId).toBe(1); expect(message.metadata.campaignId).toBeUndefined(); @@ -131,7 +130,7 @@ describe('IterableEmbeddedMessage', () => { const message = new IterableEmbeddedMessage(dict); expect(message).toBeInstanceOf(IterableEmbeddedMessage); - expect(message.metadata).toBeInstanceOf(IterableEmbeddedMessageMetadata); + expect(message.metadata).toBeInstanceOf(Object); expect(message.elements).toBeInstanceOf(IterableEmbeddedMessageElements); expect(message.elements?.title).toBe('Elements Only'); expect(message.elements?.body).toBe('No payload here'); @@ -155,7 +154,7 @@ describe('IterableEmbeddedMessage', () => { const message = new IterableEmbeddedMessage(dict); expect(message).toBeInstanceOf(IterableEmbeddedMessage); - expect(message.metadata).toBeInstanceOf(IterableEmbeddedMessageMetadata); + expect(message.metadata).toBeInstanceOf(Object); expect(message.elements).toBeUndefined(); expect(message.payload).toEqual({ someData: 'someValue', From 2b627f30d06b17f7ae383490efbc1ee5e0064dc6 Mon Sep 17 00:00:00 2001 From: Evan Greer Date: Thu, 26 Jun 2025 16:50:48 -0600 Subject: [PATCH 29/30] feat: removes embedded metadata class --- .../IterableEmbeddedMessageMetadata.test.ts | 59 ------------------- .../IterableEmbeddedMessageMetadata.ts | 38 ------------ src/embedded/classes/index.ts | 4 +- 3 files changed, 3 insertions(+), 98 deletions(-) delete mode 100644 src/__tests__/IterableEmbeddedMessageMetadata.test.ts delete mode 100644 src/embedded/classes/IterableEmbeddedMessageMetadata.ts diff --git a/src/__tests__/IterableEmbeddedMessageMetadata.test.ts b/src/__tests__/IterableEmbeddedMessageMetadata.test.ts deleted file mode 100644 index 8f03a5287..000000000 --- a/src/__tests__/IterableEmbeddedMessageMetadata.test.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { IterableEmbeddedMessageMetadata } from '../embedded/classes/IterableEmbeddedMessageMetadata'; -import { Iterable } from '../core'; - -describe('IterableEmbeddedMessage', () => { - test('should create an instance of IterableEmbeddedMessageMetadata from a dictionary', () => { - Iterable.logger.log( - 'iterableEmbeddedMessageMetadata_fromDict_valid_dictionary' - ); - - const dict = { - messageId: '123', - placementId: 456, - campaignId: 789, - isProof: false, - }; - - const result = new IterableEmbeddedMessageMetadata(dict); - - expect(result).toBeInstanceOf(IterableEmbeddedMessageMetadata); - expect(result.messageId).toBe('123'); - expect(result.placementId).toBe(456); - expect(result.campaignId).toBe(789); - expect(result.isProof).toBe(false); - }); - - test('should handle optional fields', () => { - Iterable.logger.log( - 'iterableEmbeddedMessageMetadata_fromDict_optional_fields_omitted' - ); - - const dict = { - messageId: '123', - placementId: 456, - }; - - const result = new IterableEmbeddedMessageMetadata(dict); - - expect(result).toBeInstanceOf(IterableEmbeddedMessageMetadata); - expect(result.messageId).toBe('123'); - expect(result.placementId).toBe(456); - expect(result.campaignId).toBeUndefined(); - expect(result.isProof).toBe(false); - }); - - test('should throw an error if messageId is not provided', () => { - Iterable.logger.log( - 'iterableEmbeddedMessageMetadata_fromDict_missing_messageId' - ); - - const dict = { - placementId: 456, - }; - - expect(() => { - // @ts-expect-error - messageId is purposely missing - new IterableEmbeddedMessageMetadata(dict); - }).toThrow('messageId and placementId are required'); - }); -}); diff --git a/src/embedded/classes/IterableEmbeddedMessageMetadata.ts b/src/embedded/classes/IterableEmbeddedMessageMetadata.ts deleted file mode 100644 index 8be0cfa5c..000000000 --- a/src/embedded/classes/IterableEmbeddedMessageMetadata.ts +++ /dev/null @@ -1,38 +0,0 @@ -/** - * Metadata for an embedded message. - */ -export class IterableEmbeddedMessageMetadata { - /** The ID for the embedded message */ - readonly messageId: string; - /** The placement ID for the embedded message */ - readonly placementId: number; - /** The campaign ID for the embedded message */ - readonly campaignId?: number; - /** Whether the embedded message is a proof */ - readonly isProof: boolean; - - /** - * Constructs an instance of IterableEmbeddedMessageMetadata. - * - * @param dict - The dictionary object containing the metadata properties. - */ - constructor(dict: EmbeddedMessageMetadataDict) { - if (!dict.messageId || !dict.placementId) { - throw new Error('messageId and placementId are required'); - } - this.messageId = dict.messageId; - this.placementId = dict.placementId; - this.campaignId = dict.campaignId; - this.isProof = dict.isProof ?? false; - } -} - -/** - * An interface defining the dictionary object containing the metadata properties for an embedded message. - */ -export interface EmbeddedMessageMetadataDict { - messageId: string; - placementId: number; - campaignId?: number; - isProof?: boolean; -} diff --git a/src/embedded/classes/index.ts b/src/embedded/classes/index.ts index 5b943168e..578dc28be 100644 --- a/src/embedded/classes/index.ts +++ b/src/embedded/classes/index.ts @@ -1,4 +1,6 @@ export * from './IterableEmbeddedManager'; export * from './IterableEmbeddedPlacement'; +export * from './IterableEmbeddedMessage'; +export * from './IterableEmbeddedMessageElements'; export * from './IterableEmbeddedMessageElementsButton'; -export * from './IterableEmbeddedMessageMetadata'; +export * from './IterableEmbeddedMessageText'; From 6701a64498d7b47a85f8f046fa1ac6bec3d6802f Mon Sep 17 00:00:00 2001 From: Evan Greer Date: Fri, 27 Jun 2025 10:17:01 -0600 Subject: [PATCH 30/30] feat: combines message and elements in one class --- src/__tests__/IterableEmbeddedMessage.test.ts | 5 +- ... => IterableEmbeddedMessageButton.test.ts} | 20 +- .../IterableEmbeddedMessageElements.test.ts | 209 ------------------ .../classes/IterableEmbeddedMessage.ts | 88 +++++++- ...on.ts => IterableEmbeddedMessageButton.ts} | 6 +- .../IterableEmbeddedMessageElements.ts | 76 ------- src/embedded/classes/index.ts | 3 +- 7 files changed, 99 insertions(+), 308 deletions(-) rename src/__tests__/{IterableEmbeddedMessageElementsButton.test.ts => IterableEmbeddedMessageButton.test.ts} (73%) delete mode 100644 src/__tests__/IterableEmbeddedMessageElements.test.ts rename src/embedded/classes/{IterableEmbeddedMessageElementsButton.ts => IterableEmbeddedMessageButton.ts} (84%) delete mode 100644 src/embedded/classes/IterableEmbeddedMessageElements.ts diff --git a/src/__tests__/IterableEmbeddedMessage.test.ts b/src/__tests__/IterableEmbeddedMessage.test.ts index fdcb145ef..3e8a99b7c 100644 --- a/src/__tests__/IterableEmbeddedMessage.test.ts +++ b/src/__tests__/IterableEmbeddedMessage.test.ts @@ -1,5 +1,4 @@ import { IterableEmbeddedMessage } from '../embedded/classes/IterableEmbeddedMessage'; -import { IterableEmbeddedMessageElements } from '../embedded/classes/IterableEmbeddedMessageElements'; import { Iterable } from '../core/classes/Iterable'; describe('IterableEmbeddedMessage', () => { @@ -58,7 +57,7 @@ describe('IterableEmbeddedMessage', () => { expect(message.metadata.isProof).toBe(false); // Check elements - expect(message.elements).toBeInstanceOf(IterableEmbeddedMessageElements); + expect(message.elements).toBeInstanceOf(Object); expect(message.elements?.title).toBe('Awesome Title'); expect(message.elements?.body).toBe('Radical Body Text'); expect(message.elements?.mediaUrl).toBe('https://example.com/image.jpg'); @@ -131,7 +130,7 @@ describe('IterableEmbeddedMessage', () => { expect(message).toBeInstanceOf(IterableEmbeddedMessage); expect(message.metadata).toBeInstanceOf(Object); - expect(message.elements).toBeInstanceOf(IterableEmbeddedMessageElements); + expect(message.elements).toBeInstanceOf(Object); expect(message.elements?.title).toBe('Elements Only'); expect(message.elements?.body).toBe('No payload here'); expect(message.payload).toBeUndefined(); diff --git a/src/__tests__/IterableEmbeddedMessageElementsButton.test.ts b/src/__tests__/IterableEmbeddedMessageButton.test.ts similarity index 73% rename from src/__tests__/IterableEmbeddedMessageElementsButton.test.ts rename to src/__tests__/IterableEmbeddedMessageButton.test.ts index b9dcf1d7b..5e20f90c0 100644 --- a/src/__tests__/IterableEmbeddedMessageElementsButton.test.ts +++ b/src/__tests__/IterableEmbeddedMessageButton.test.ts @@ -1,4 +1,4 @@ -import { IterableEmbeddedMessageElementsButton } from '../embedded/classes/IterableEmbeddedMessageElementsButton'; +import { IterableEmbeddedMessageButton } from '../embedded/classes/IterableEmbeddedMessageButton'; import { Iterable } from '../core/classes/Iterable'; describe('IterableEmbeddedMessageButton', () => { @@ -13,9 +13,9 @@ describe('IterableEmbeddedMessageButton', () => { action: { type: 'openUrl', data: 'https://example.com' }, }; - const button = new IterableEmbeddedMessageElementsButton(dict); + const button = new IterableEmbeddedMessageButton(dict); - expect(button).toBeInstanceOf(IterableEmbeddedMessageElementsButton); + expect(button).toBeInstanceOf(IterableEmbeddedMessageButton); expect(button.id).toBe('button-123'); expect(button.title).toBe('Click Me!'); expect(button.action).toBeInstanceOf(Object); @@ -28,9 +28,9 @@ describe('IterableEmbeddedMessageButton', () => { const dict = { id: 'button-123' }; - const button = new IterableEmbeddedMessageElementsButton(dict); + const button = new IterableEmbeddedMessageButton(dict); - expect(button).toBeInstanceOf(IterableEmbeddedMessageElementsButton); + expect(button).toBeInstanceOf(IterableEmbeddedMessageButton); expect(button.id).toBe('button-123'); expect(button.title).toBeUndefined(); expect(button.action).toBeUndefined(); @@ -44,9 +44,9 @@ describe('IterableEmbeddedMessageButton', () => { title: 'Click Me!', }; - const button = new IterableEmbeddedMessageElementsButton(dict); + const button = new IterableEmbeddedMessageButton(dict); - expect(button).toBeInstanceOf(IterableEmbeddedMessageElementsButton); + expect(button).toBeInstanceOf(IterableEmbeddedMessageButton); expect(button.id).toBe('button-123'); expect(button.title).toBe('Click Me!'); expect(button.action).toBeUndefined(); @@ -60,7 +60,7 @@ describe('IterableEmbeddedMessageButton', () => { action: { type: 'openUrl', data: 'https://example.com' }, }; // @ts-expect-error - id is purposely missing - expect(() => new IterableEmbeddedMessageElementsButton(dict)).toThrow( + expect(() => new IterableEmbeddedMessageButton(dict)).toThrow( 'id is required' ); }); @@ -75,9 +75,9 @@ describe('IterableEmbeddedMessageButton', () => { action: { type: 'close' }, }; - const button = new IterableEmbeddedMessageElementsButton(dict); + const button = new IterableEmbeddedMessageButton(dict); - expect(button).toBeInstanceOf(IterableEmbeddedMessageElementsButton); + expect(button).toBeInstanceOf(IterableEmbeddedMessageButton); expect(button.id).toBe('button-123'); expect(button.action).toBeInstanceOf(Object); expect(button.action?.type).toBe('close'); diff --git a/src/__tests__/IterableEmbeddedMessageElements.test.ts b/src/__tests__/IterableEmbeddedMessageElements.test.ts deleted file mode 100644 index 64df9021a..000000000 --- a/src/__tests__/IterableEmbeddedMessageElements.test.ts +++ /dev/null @@ -1,209 +0,0 @@ -import { IterableEmbeddedMessageElements } from '../embedded/classes/IterableEmbeddedMessageElements'; -import { IterableEmbeddedMessageElementsButton } from '../embedded/classes/IterableEmbeddedMessageElementsButton'; -import { IterableEmbeddedMessageText } from '../embedded/classes/IterableEmbeddedMessageText'; -import { Iterable } from '../core/classes/Iterable'; - -describe('IterableEmbeddedMessageElements', () => { - it('should create an instance with all properties', () => { - Iterable.logger.log( - 'iterableEmbeddedMessageElements_fromDict_all_properties' - ); - - const dict = { - title: 'Awesome Title', - body: 'Radical Body Text', - mediaUrl: 'https://example.com/image.jpg', - mediaUrlCaption: 'Check out this sick image!', - defaultAction: { - type: 'openUrl', - data: 'https://example.com', - }, - buttons: [ - { - id: 'button-1', - title: 'Click Me!', - action: { - type: 'openUrl', - data: 'https://example.com/button1', - }, - }, - { - id: 'button-2', - title: 'Close', - action: { - type: 'action://dismiss', - }, - }, - ], - text: [ - { - id: 'text-1', - text: 'Some cool text', - type: 'body', - }, - { - id: 'text-2', - text: 'More radical text', - type: 'subtitle', - }, - ], - }; - - const elements = new IterableEmbeddedMessageElements(dict); - - expect(elements).toBeInstanceOf(IterableEmbeddedMessageElements); - expect(elements.title).toBe('Awesome Title'); - expect(elements.body).toBe('Radical Body Text'); - expect(elements.mediaUrl).toBe('https://example.com/image.jpg'); - expect(elements.mediaUrlCaption).toBe('Check out this sick image!'); - - // Check defaultAction - expect(elements.defaultAction).toBeInstanceOf(Object); - expect(elements.defaultAction?.type).toBe('openUrl'); - expect(elements.defaultAction?.data).toBe('https://example.com'); - - // Check buttons - expect(elements.buttons).toHaveLength(2); - const firstButton = elements - .buttons![0] as IterableEmbeddedMessageElementsButton; - expect(firstButton).toBeInstanceOf(IterableEmbeddedMessageElementsButton); - expect(firstButton.id).toBe('button-1'); - expect(firstButton.title).toBe('Click Me!'); - expect(firstButton.action?.type).toBe('openUrl'); - expect(firstButton.action?.data).toBe('https://example.com/button1'); - - const secondButton = elements - .buttons![1] as IterableEmbeddedMessageElementsButton; - expect(secondButton).toBeInstanceOf(IterableEmbeddedMessageElementsButton); - expect(secondButton.id).toBe('button-2'); - expect(secondButton.title).toBe('Close'); - expect(secondButton.action?.type).toBe('action://dismiss'); - expect(secondButton.action?.data).toBeUndefined(); - - // Check text elements - expect(elements.text).toHaveLength(2); - const firstText = elements.text![0] as IterableEmbeddedMessageText; - expect(firstText).toBeInstanceOf(IterableEmbeddedMessageText); - expect(firstText.id).toBe('text-1'); - expect(firstText.text).toBe('Some cool text'); - expect(firstText.type).toBe('body'); - - const secondText = elements.text![1] as IterableEmbeddedMessageText; - expect(secondText).toBeInstanceOf(IterableEmbeddedMessageText); - expect(secondText.id).toBe('text-2'); - expect(secondText.text).toBe('More radical text'); - expect(secondText.type).toBe('subtitle'); - }); - - it('should create an instance with title and body', () => { - Iterable.logger.log( - 'iterableEmbeddedMessageElements_fromDict_title_and_body' - ); - - const dict = { - title: 'Simple Title', - body: 'Simple Body', - }; - - const elements = new IterableEmbeddedMessageElements(dict); - - expect(elements).toBeInstanceOf(IterableEmbeddedMessageElements); - expect(elements.title).toBe('Simple Title'); - expect(elements.body).toBe('Simple Body'); - expect(elements.mediaUrl).toBeUndefined(); - expect(elements.mediaUrlCaption).toBeUndefined(); - expect(elements.defaultAction).toBeUndefined(); - expect(elements.buttons).toBeUndefined(); - expect(elements.text).toBeUndefined(); - }); - - it('should create an instance with no title or body', () => { - Iterable.logger.log( - 'iterableEmbeddedMessageElements_fromDict_no_title_or_body' - ); - - const dict = {}; - - const elements = new IterableEmbeddedMessageElements(dict); - - expect(elements).toBeInstanceOf(IterableEmbeddedMessageElements); - expect(elements.title).toBeUndefined(); - expect(elements.body).toBeUndefined(); - expect(elements.mediaUrl).toBeUndefined(); - expect(elements.mediaUrlCaption).toBeUndefined(); - expect(elements.defaultAction).toBeUndefined(); - expect(elements.buttons).toBeUndefined(); - expect(elements.text).toBeUndefined(); - }); - - it('should create an instance with media properties', () => { - Iterable.logger.log( - 'iterableEmbeddedMessageElements_fromDict_media_properties' - ); - - const dict = { - title: 'Media Title', - body: 'Media Body', - mediaUrl: 'https://example.com/media.jpg', - mediaUrlCaption: 'Check this out!', - }; - - const elements = new IterableEmbeddedMessageElements(dict); - - expect(elements).toBeInstanceOf(IterableEmbeddedMessageElements); - expect(elements.title).toBe('Media Title'); - expect(elements.body).toBe('Media Body'); - expect(elements.mediaUrl).toBe('https://example.com/media.jpg'); - expect(elements.mediaUrlCaption).toBe('Check this out!'); - expect(elements.defaultAction).toBeUndefined(); - expect(elements.buttons).toBeUndefined(); - expect(elements.text).toBeUndefined(); - }); - - it('should create an instance with defaultAction only', () => { - Iterable.logger.log( - 'iterableEmbeddedMessageElements_fromDict_defaultAction_only' - ); - - const dict = { - title: 'Action Title', - body: 'Action Body', - defaultAction: { - type: 'openUrl', - data: 'https://example.com', - }, - }; - - const elements = new IterableEmbeddedMessageElements(dict); - - expect(elements).toBeInstanceOf(IterableEmbeddedMessageElements); - expect(elements.title).toBe('Action Title'); - expect(elements.body).toBe('Action Body'); - expect(elements.defaultAction).toBeInstanceOf(Object); - expect(elements.defaultAction?.type).toBe('openUrl'); - expect(elements.defaultAction?.data).toBe('https://example.com'); - expect(elements.buttons).toBeUndefined(); - expect(elements.text).toBeUndefined(); - }); - - it('should create an instance with empty arrays for buttons and text', () => { - Iterable.logger.log( - 'iterableEmbeddedMessageElements_fromDict_empty_arrays' - ); - - const dict = { - title: 'Empty Arrays Title', - body: 'Empty Arrays Body', - buttons: [], - text: [], - }; - - const elements = new IterableEmbeddedMessageElements(dict); - - expect(elements).toBeInstanceOf(IterableEmbeddedMessageElements); - expect(elements.title).toBe('Empty Arrays Title'); - expect(elements.body).toBe('Empty Arrays Body'); - expect(elements.buttons).toHaveLength(0); - expect(elements.text).toHaveLength(0); - }); -}); diff --git a/src/embedded/classes/IterableEmbeddedMessage.ts b/src/embedded/classes/IterableEmbeddedMessage.ts index c3fbe9607..9d528504d 100644 --- a/src/embedded/classes/IterableEmbeddedMessage.ts +++ b/src/embedded/classes/IterableEmbeddedMessage.ts @@ -1,5 +1,5 @@ -import { IterableEmbeddedMessageElements } from './IterableEmbeddedMessageElements'; -import type { EmbeddedMessageElementsDict } from './IterableEmbeddedMessageElements'; +import { IterableEmbeddedMessageButton } from './IterableEmbeddedMessageButton'; +import { IterableEmbeddedMessageText } from './IterableEmbeddedMessageText'; /** * IterableEmbeddedMessage represents an embedded message. @@ -7,13 +7,37 @@ import type { EmbeddedMessageElementsDict } from './IterableEmbeddedMessageEleme export class IterableEmbeddedMessage { /** The metadata of the embedded message */ readonly metadata: { + /** The id of the message */ messageId: string; + /** The placement id of the message */ placementId: number; + /** The campaign id of the message */ campaignId?: number; + /** Whether the message is a proof */ isProof: boolean; }; /** The elements of the embedded message */ - readonly elements?: IterableEmbeddedMessageElements; + readonly elements?: { + /** The title of the embedded message */ + title?: string; + /** The body of the embedded message */ + body?: string; + /** The media url of the embedded message */ + mediaUrl?: string; + /** The media url caption of the embedded message */ + mediaUrlCaption?: string; + /** The default action of the embedded message */ + defaultAction?: { + /** The type of action */ + type: string; + /** The url for the action when the type is `openUrl` */ + data?: string; + }; + /** The buttons of the embedded message */ + buttons?: IterableEmbeddedMessageButton[]; + /** The text of the embedded message */ + text?: IterableEmbeddedMessageText[]; + }; /** The custom payload of the embedded message */ readonly payload?: Record; @@ -32,9 +56,35 @@ export class IterableEmbeddedMessage { campaignId: dict.metadata.campaignId, isProof: dict.metadata.isProof, }; - this.elements = dict.elements - ? new IterableEmbeddedMessageElements(dict.elements) - : undefined; + + if (dict.elements) { + this.elements = { + title: dict.elements?.title, + body: dict.elements?.body, + mediaUrl: dict.elements?.mediaUrl, + mediaUrlCaption: dict.elements?.mediaUrlCaption, + }; + + if (dict.elements?.defaultAction) { + this.elements.defaultAction = { + type: dict.elements.defaultAction.type, + data: dict.elements.defaultAction.data, + }; + } + + if (dict.elements?.buttons) { + this.elements.buttons = dict.elements.buttons.map( + (button) => new IterableEmbeddedMessageButton(button) + ); + } + + if (dict.elements?.text) { + this.elements.text = dict.elements.text.map( + (text) => new IterableEmbeddedMessageText(text) + ); + } + } + this.payload = dict.payload; } } @@ -45,13 +95,37 @@ export class IterableEmbeddedMessage { export interface EmbeddedMessageDict { /** The metadata of the embedded message */ metadata: { + /** The id of the message */ messageId: string; + /** The placement id of the message */ placementId: number; + /** The campaign id of the message */ campaignId?: number; + /** Whether the message is a proof */ isProof: boolean; }; /** The elements of the embedded message */ - elements?: EmbeddedMessageElementsDict; + elements?: { + /** The title of the embedded message */ + title?: string; + /** The body of the embedded message */ + body?: string; + /** The media url of the embedded message */ + mediaUrl?: string; + /** The media url caption of the embedded message */ + mediaUrlCaption?: string; + /** The default action of the embedded message */ + defaultAction?: { + /** The type of action */ + type: string; + /** The url for the action when the type is `openUrl` */ + data?: string; + }; + /** The buttons of the embedded message */ + buttons?: IterableEmbeddedMessageButton[]; + /** The text of the embedded message */ + text?: IterableEmbeddedMessageText[]; + }; /** The custom payload of the embedded message */ payload?: Record; } diff --git a/src/embedded/classes/IterableEmbeddedMessageElementsButton.ts b/src/embedded/classes/IterableEmbeddedMessageButton.ts similarity index 84% rename from src/embedded/classes/IterableEmbeddedMessageElementsButton.ts rename to src/embedded/classes/IterableEmbeddedMessageButton.ts index 7d41b50d8..9a0896d96 100644 --- a/src/embedded/classes/IterableEmbeddedMessageElementsButton.ts +++ b/src/embedded/classes/IterableEmbeddedMessageButton.ts @@ -1,14 +1,16 @@ /** * IterableEmbeddedMessageElementsButton represents a button in an embedded message. */ -export class IterableEmbeddedMessageElementsButton { +export class IterableEmbeddedMessageButton { /** The ID for the embedded message button */ readonly id: string; /** The title for the embedded message button */ readonly title?: string; /** The action for the embedded message button */ readonly action?: { + /** The type of action */ type: string; + /** The url for the action when the type is `openUrl` */ data?: string; }; @@ -44,7 +46,9 @@ export interface EmbeddedMessageElementsButtonDict { title?: string; /** The action for the embedded message button */ action?: { + /** The type of action */ type: string; + /** The url for the action when the type is `openUrl` */ data?: string; }; } diff --git a/src/embedded/classes/IterableEmbeddedMessageElements.ts b/src/embedded/classes/IterableEmbeddedMessageElements.ts deleted file mode 100644 index b5dc63b6a..000000000 --- a/src/embedded/classes/IterableEmbeddedMessageElements.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { IterableEmbeddedMessageElementsButton } from './IterableEmbeddedMessageElementsButton'; -import { IterableEmbeddedMessageText } from './IterableEmbeddedMessageText'; - -import type { EmbeddedMessageElementsButtonDict } from './IterableEmbeddedMessageElementsButton'; -import type { EmbeddedMessageTextDict } from './IterableEmbeddedMessageText'; - -/** - * IterableEmbeddedMessageElements represents the elements of an embedded message. - */ -export class IterableEmbeddedMessageElements { - /** The title of the embedded message */ - readonly title?: string; - /** The body of the embedded message */ - readonly body?: string; - /** The url of the embedded message image */ - readonly mediaUrl?: string; - /** The caption of the embedded message image */ - readonly mediaUrlCaption?: string; - /** The default action of the embedded message */ - readonly defaultAction?: { - type: string; - data?: string; - }; - /** The buttons of the embedded message */ - readonly buttons?: IterableEmbeddedMessageElementsButton[]; - /** The text elements of the embedded message */ - readonly text?: IterableEmbeddedMessageText[]; - - /** - * Creates an instance of `IterableEmbeddedMessageElements`. - * - * @param dict - The dictionary object containing the properties to initialize the `IterableEmbeddedMessageElements` instance. - */ - constructor(dict: Partial) { - this.title = dict.title; - this.body = dict.body; - this.mediaUrl = dict.mediaUrl; - this.mediaUrlCaption = dict.mediaUrlCaption; - - if (dict.defaultAction) { - this.defaultAction = { - type: dict.defaultAction.type, - data: dict.defaultAction.data, - }; - } - - this.buttons = dict.buttons?.map( - (button) => new IterableEmbeddedMessageElementsButton(button) - ); - - this.text = dict.text?.map((text) => new IterableEmbeddedMessageText(text)); - } -} - -/** - * An interface defining the dictionary object containing the properties for the embedded message elements. - */ -export interface EmbeddedMessageElementsDict { - /** The title of the embedded message */ - title?: string; - /** The body of the embedded message */ - body?: string; - /** The url of the embedded message image */ - mediaUrl?: string; - /** The caption of the embedded message image */ - mediaUrlCaption?: string; - /** The default action of the embedded message */ - defaultAction?: { - type: string; - data?: string; - }; - /** The buttons of the embedded message */ - buttons?: EmbeddedMessageElementsButtonDict[]; - /** The text elements of the embedded message */ - text?: EmbeddedMessageTextDict[]; -} diff --git a/src/embedded/classes/index.ts b/src/embedded/classes/index.ts index 578dc28be..2a2abba63 100644 --- a/src/embedded/classes/index.ts +++ b/src/embedded/classes/index.ts @@ -1,6 +1,5 @@ export * from './IterableEmbeddedManager'; export * from './IterableEmbeddedPlacement'; export * from './IterableEmbeddedMessage'; -export * from './IterableEmbeddedMessageElements'; -export * from './IterableEmbeddedMessageElementsButton'; +export * from './IterableEmbeddedMessageButton'; export * from './IterableEmbeddedMessageText';