diff --git a/example/src/components/Commerce/Commerce.tsx b/example/src/components/Commerce/Commerce.tsx
index c840f9199..134a37706 100644
--- a/example/src/components/Commerce/Commerce.tsx
+++ b/example/src/components/Commerce/Commerce.tsx
@@ -1,4 +1,5 @@
import { Alert, Image, Pressable, ScrollView, Text, View } from 'react-native';
+import { SafeAreaView } from 'react-native-safe-area-context';
import { Iterable, IterableCommerceItem } from '@iterable/react-native-sdk';
@@ -32,35 +33,37 @@ export const Commerce = () => {
};
return (
-
-
- Commerce
-
- Purchase will be tracked when "Buy" is clicked. See logs for
- output.
-
- {items.map((item) => (
-
-
-
-
-
-
- {item.name}
- {item.subtitle}
- ${item.price}
- handleClick(item)}
- >
- Buy
-
+
+
+
+ Commerce
+
+ Purchase will be tracked when "Buy" is clicked. See logs for
+ output.
+
+ {items.map((item) => (
+
+
+
+
+
+
+ {item.name}
+ {item.subtitle}
+ ${item.price}
+ handleClick(item)}
+ >
+ Buy
+
+
-
- ))}
-
-
+ ))}
+
+
+
);
};
diff --git a/example/src/components/Embedded/Embedded.tsx b/example/src/components/Embedded/Embedded.tsx
index 806bb0c23..3306e2cc4 100644
--- a/example/src/components/Embedded/Embedded.tsx
+++ b/example/src/components/Embedded/Embedded.tsx
@@ -1,12 +1,21 @@
-import { Text, View } from 'react-native';
+import { Iterable } from '@iterable/react-native-sdk';
+import { Text } from 'react-native';
+import { SafeAreaView } from 'react-native-safe-area-context';
import styles from './Embedded.styles';
export const Embedded = () => {
return (
-
+
EMBEDDED
-
+
+ Does embedded class exist? {Iterable.embeddedManager ? 'Yes' : 'No'}
+
+
+ Is embedded manager enabled?{' '}
+ {Iterable.embeddedManager.isEnabled ? 'Yes' : 'No'}
+
+
);
};
diff --git a/example/src/components/Login/Login.tsx b/example/src/components/Login/Login.tsx
index 9712792ed..988e9c8db 100644
--- a/example/src/components/Login/Login.tsx
+++ b/example/src/components/Login/Login.tsx
@@ -1,3 +1,4 @@
+import { useMemo } from 'react';
import {
ActivityIndicator,
Pressable,
@@ -5,7 +6,7 @@ import {
TextInput,
View,
} from 'react-native';
-import { useMemo } from 'react';
+import { SafeAreaView } from 'react-native-safe-area-context';
import { colors, type Route } from '../../constants';
import { useIterableApp } from '../../hooks';
@@ -18,7 +19,7 @@ export const Login = ({ navigation }: RootStackScreenProps) => {
const loginIsEnabled = useMemo(() => apiKey && userId, [apiKey, userId]);
return (
-
+
{loginInProgress ? (
@@ -66,7 +67,7 @@ export const Login = ({ navigation }: RootStackScreenProps) => {
>
)}
-
+
);
};
diff --git a/example/src/components/User/User.tsx b/example/src/components/User/User.tsx
index 23f8361a5..4f3ee5be1 100644
--- a/example/src/components/User/User.tsx
+++ b/example/src/components/User/User.tsx
@@ -1,6 +1,7 @@
import { Iterable } from '@iterable/react-native-sdk';
import { useEffect, useState } from 'react';
-import { Text, TouchableOpacity, View } from 'react-native';
+import { Text, TouchableOpacity } from 'react-native';
+import { SafeAreaView } from 'react-native-safe-area-context';
import { useIterableApp } from '../../hooks';
import styles from './User.styles';
@@ -18,13 +19,13 @@ export const User = () => {
}, [isLoggedIn]);
return (
-
+
Welcome Iterator
Logged in as {loggedInAs}
Logout
-
+
);
};
diff --git a/example/src/constants/styles/typography.ts b/example/src/constants/styles/typography.ts
index 09b6c2405..af8a3b8e4 100644
--- a/example/src/constants/styles/typography.ts
+++ b/example/src/constants/styles/typography.ts
@@ -6,7 +6,6 @@ export const appName: TextStyle = {
fontWeight: 'bold',
fontSize: 14,
width: '100%',
- marginTop: 41,
marginBottom: 64,
textTransform: 'uppercase',
letterSpacing: 2,
diff --git a/example/src/hooks/useIterableApp.tsx b/example/src/hooks/useIterableApp.tsx
index 9f72f0cf8..f47f58ba1 100644
--- a/example/src/hooks/useIterableApp.tsx
+++ b/example/src/hooks/useIterableApp.tsx
@@ -192,6 +192,8 @@ export const IterableAppProvider: FunctionComponent<
config.logLevel = IterableLogLevel.debug;
+ config.embeddedMessagingEnabled = true;
+
config.inAppHandler = () => IterableInAppShowResponse.show;
if (
diff --git a/src/core/classes/Iterable.test.ts b/src/core/classes/Iterable.test.ts
index bfe4c26f6..1da4e4e00 100644
--- a/src/core/classes/Iterable.test.ts
+++ b/src/core/classes/Iterable.test.ts
@@ -300,37 +300,39 @@ describe('Iterable', () => {
// WHEN config is initialized
const config = new IterableConfig();
// THEN config has default values
- expect(config.pushIntegrationName).toBe(undefined);
+ expect(config.allowedProtocols).toEqual([]);
+ expect(config.androidSdkUseInMemoryStorageForInApps).toBe(false);
+ expect(config.authHandler).toBe(undefined);
expect(config.autoPushRegistration).toBe(true);
expect(config.checkForDeferredDeeplink).toBe(false);
- expect(config.inAppDisplayInterval).toBe(30.0);
- expect(config.urlHandler).toBe(undefined);
expect(config.customActionHandler).toBe(undefined);
+ expect(config.dataRegion).toBe(IterableDataRegion.US);
+ expect(config.embeddedMessagingEnabled).toBe(false);
+ expect(config.encryptionEnforced).toBe(false);
+ expect(config.expiringAuthTokenRefreshPeriod).toBe(60.0);
+ expect(config.inAppDisplayInterval).toBe(30.0);
expect(config.inAppHandler).toBe(undefined);
- expect(config.authHandler).toBe(undefined);
expect(config.logLevel).toBe(IterableLogLevel.debug);
expect(config.logReactNativeSdkCalls).toBe(true);
- expect(config.expiringAuthTokenRefreshPeriod).toBe(60.0);
- expect(config.allowedProtocols).toEqual([]);
- expect(config.androidSdkUseInMemoryStorageForInApps).toBe(false);
+ expect(config.pushIntegrationName).toBe(undefined);
+ expect(config.urlHandler).toBe(undefined);
expect(config.useInMemoryStorageForInApps).toBe(false);
- expect(config.dataRegion).toBe(IterableDataRegion.US);
- expect(config.encryptionEnforced).toBe(false);
const configDict = config.toDict();
- expect(configDict.pushIntegrationName).toBe(undefined);
+ expect(configDict.allowedProtocols).toEqual([]);
+ expect(configDict.androidSdkUseInMemoryStorageForInApps).toBe(false);
+ expect(configDict.authHandlerPresent).toBe(false);
expect(configDict.autoPushRegistration).toBe(true);
- expect(configDict.inAppDisplayInterval).toBe(30.0);
- expect(configDict.urlHandlerPresent).toBe(false);
expect(configDict.customActionHandlerPresent).toBe(false);
+ expect(configDict.dataRegion).toBe(IterableDataRegion.US);
+ expect(configDict.embeddedMessagingEnabled).toBe(false);
+ expect(configDict.encryptionEnforced).toBe(false);
+ expect(configDict.expiringAuthTokenRefreshPeriod).toBe(60.0);
+ expect(configDict.inAppDisplayInterval).toBe(30.0);
expect(configDict.inAppHandlerPresent).toBe(false);
- expect(configDict.authHandlerPresent).toBe(false);
expect(configDict.logLevel).toBe(IterableLogLevel.debug);
- expect(configDict.expiringAuthTokenRefreshPeriod).toBe(60.0);
- expect(configDict.allowedProtocols).toEqual([]);
- expect(configDict.androidSdkUseInMemoryStorageForInApps).toBe(false);
+ expect(configDict.pushIntegrationName).toBe(undefined);
+ expect(configDict.urlHandlerPresent).toBe(false);
expect(configDict.useInMemoryStorageForInApps).toBe(false);
- expect(configDict.dataRegion).toBe(IterableDataRegion.US);
- expect(configDict.encryptionEnforced).toBe(false);
});
});
@@ -1212,4 +1214,19 @@ describe('Iterable', () => {
});
});
});
+
+ describe('embeddedManager', () => {
+ it('should be disabled by default', () => {
+ const config = new IterableConfig();
+ expect(config.embeddedMessagingEnabled).toBe(false);
+ expect(Iterable.embeddedManager.isEnabled).toBe(false);
+ });
+
+ it('should enable embeddedManager when config is set', async () => {
+ const config = new IterableConfig();
+ config.embeddedMessagingEnabled = true;
+ await Iterable.initialize('test-key', config);
+ expect(Iterable.embeddedManager.isEnabled).toBe(true);
+ });
+ });
});
diff --git a/src/core/classes/Iterable.ts b/src/core/classes/Iterable.ts
index 365aee94f..fa11f9a16 100644
--- a/src/core/classes/Iterable.ts
+++ b/src/core/classes/Iterable.ts
@@ -20,6 +20,7 @@ import { IterableAuthResponse } from './IterableAuthResponse';
import type { IterableCommerceItem } from './IterableCommerceItem';
import { IterableConfig } from './IterableConfig';
import { IterableLogger } from './IterableLogger';
+import { IterableEmbeddedManager } from '../../embedded/classes/IterableEmbeddedManager';
const RNEventEmitter = new NativeEventEmitter(RNIterableAPI);
@@ -96,6 +97,27 @@ export class Iterable {
*/
static authManager: IterableAuthManager = new IterableAuthManager();
+ /**
+ * Embedded message manager for the current user.
+ *
+ * This property provides access to embedded message functionality including
+ * retrieving messages, displaying messages, removing messages, and more.
+ *
+ * **Documentation**
+ * - [Embedded Messaging Overview](https://support.iterable.com/hc/en-us/articles/23060529977364-Embedded-Messaging-Overview)
+ * - [Android Embedded Messaging](https://support.iterable.com/hc/en-us/articles/23061877893652-Embedded-Messages-with-Iterable-s-Android-SDK)
+ * - [iOS Embedded Messaging](https://support.iterable.com/hc/en-us/articles/23061840746900-Embedded-Messages-with-Iterable-s-iOS-SDK)
+ *
+ * @example
+ * ```typescript
+ * Iterable.embeddedManager.getMessages().then(messages => {
+ * console.log('Messages:', messages);
+ * });
+ * ```
+ */
+ static embeddedManager: IterableEmbeddedManager =
+ new IterableEmbeddedManager();
+
/**
* Initializes the Iterable React Native SDK in your app's Javascript or Typescript code.
*
@@ -172,6 +194,10 @@ export class Iterable {
IterableLogger.setLoggingEnabled(config.logReactNativeSdkCalls ?? true);
IterableLogger.setLogLevel(config.logLevel);
+
+ Iterable.embeddedManager.setEnabled(
+ config.embeddedMessagingEnabled ?? false
+ );
}
this.setupEventHandlers();
diff --git a/src/core/classes/IterableConfig.ts b/src/core/classes/IterableConfig.ts
index b357f37bb..a14faf550 100644
--- a/src/core/classes/IterableConfig.ts
+++ b/src/core/classes/IterableConfig.ts
@@ -329,6 +329,16 @@ export class IterableConfig {
*/
encryptionEnforced = false;
+ /**
+ * Should the SDK enable and use embedded messaging?
+ *
+ * **Documentation**
+ * - [Embedded Messaging Overview](https://support.iterable.com/hc/en-us/articles/23060529977364-Embedded-Messaging-Overview)
+ * - [Android Embedded Messaging](https://support.iterable.com/hc/en-us/articles/23061877893652-Embedded-Messages-with-Iterable-s-Android-SDK)
+ * - [iOS Embedded Messaging](https://support.iterable.com/hc/en-us/articles/23061840746900-Embedded-Messages-with-Iterable-s-iOS-SDK)
+ */
+ embeddedMessagingEnabled = false;
+
/**
* Converts the IterableConfig instance to a dictionary object.
*
@@ -378,6 +388,7 @@ export class IterableConfig {
pushPlatform: this.pushPlatform,
encryptionEnforced: this.encryptionEnforced,
retryPolicy: this.retryPolicy,
+ embeddedMessagingEnabled: this.embeddedMessagingEnabled,
};
}
}
diff --git a/src/embedded/classes/IterableEmbeddedManager.test.ts b/src/embedded/classes/IterableEmbeddedManager.test.ts
new file mode 100644
index 000000000..96a09ddf4
--- /dev/null
+++ b/src/embedded/classes/IterableEmbeddedManager.test.ts
@@ -0,0 +1,59 @@
+import { IterableEmbeddedManager } from './IterableEmbeddedManager';
+
+describe('IterableEmbeddedManager', () => {
+ let embeddedManager: IterableEmbeddedManager;
+
+ beforeEach(() => {
+ embeddedManager = new IterableEmbeddedManager();
+ });
+
+ describe('isEnabled', () => {
+ it('should be false by default', () => {
+ expect(embeddedManager.isEnabled).toBe(false);
+ });
+
+ it('should return true after being enabled', () => {
+ embeddedManager.setEnabled(true);
+ expect(embeddedManager.isEnabled).toBe(true);
+ });
+
+ it('should return false after being disabled', () => {
+ embeddedManager.setEnabled(false);
+ expect(embeddedManager.isEnabled).toBe(false);
+ });
+ });
+
+ describe('setEnabled', () => {
+ it('should enable the embedded manager', () => {
+ embeddedManager.setEnabled(true);
+ expect(embeddedManager.isEnabled).toBe(true);
+ });
+
+ it('should disable the embedded manager', () => {
+ embeddedManager.setEnabled(false);
+ expect(embeddedManager.isEnabled).toBe(false);
+ });
+
+ it('should toggle enabled state multiple times', () => {
+ embeddedManager.setEnabled(true);
+ expect(embeddedManager.isEnabled).toBe(true);
+
+ embeddedManager.setEnabled(false);
+ expect(embeddedManager.isEnabled).toBe(false);
+
+ embeddedManager.setEnabled(true);
+ expect(embeddedManager.isEnabled).toBe(true);
+ });
+
+ it('should handle setting the same state multiple times', () => {
+ embeddedManager.setEnabled(true);
+ embeddedManager.setEnabled(true);
+ expect(embeddedManager.isEnabled).toBe(true);
+
+ embeddedManager.setEnabled(false);
+ embeddedManager.setEnabled(false);
+ expect(embeddedManager.isEnabled).toBe(false);
+ });
+ });
+});
+
diff --git a/src/embedded/classes/IterableEmbeddedManager.ts b/src/embedded/classes/IterableEmbeddedManager.ts
new file mode 100644
index 000000000..13a59ddda
--- /dev/null
+++ b/src/embedded/classes/IterableEmbeddedManager.ts
@@ -0,0 +1,33 @@
+/**
+ * Manages embedded messages from Iterable.
+ *
+ * Provides embedded message functionality including retrieving messages,
+ * displaying messages, removing messages, and more.
+ *
+ * **Documentation**
+ * - [Embedded Messaging Overview](https://support.iterable.com/hc/en-us/articles/23060529977364-Embedded-Messaging-Overview)
+ * - [Android Embedded Messaging](https://support.iterable.com/hc/en-us/articles/23061877893652-Embedded-Messages-with-Iterable-s-Android-SDK)
+ * - [iOS Embedded Messaging](https://support.iterable.com/hc/en-us/articles/23061840746900-Embedded-Messages-with-Iterable-s-iOS-SDK)
+ */
+export class IterableEmbeddedManager {
+ /**
+ * Whether the embedded manager is enabled.
+ */
+ private _isEnabled = false;
+
+ /**
+ * Gets whether the embedded manager is enabled.
+ */
+ get isEnabled(): boolean {
+ return this._isEnabled;
+ }
+
+ /**
+ * Sets whether the embedded manager is enabled.
+ *
+ * @param enabled - Whether the embedded manager is enabled.
+ */
+ setEnabled(enabled: boolean) {
+ this._isEnabled = enabled;
+ }
+}
diff --git a/src/embedded/classes/index.ts b/src/embedded/classes/index.ts
new file mode 100644
index 000000000..be2af76f0
--- /dev/null
+++ b/src/embedded/classes/index.ts
@@ -0,0 +1 @@
+export * from './IterableEmbeddedManager';
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 240ac51f5..c9a014340 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -59,3 +59,4 @@ export {
type IterableInboxProps,
type IterableInboxRowViewModel,
} from './inbox';
+export { IterableEmbeddedManager } from './embedded';