diff --git a/example/src/components/Embedded/Embedded.styles.ts b/example/src/components/Embedded/Embedded.styles.ts index 56241c676..0574484ea 100644 --- a/example/src/components/Embedded/Embedded.styles.ts +++ b/example/src/components/Embedded/Embedded.styles.ts @@ -1,5 +1,12 @@ import { StyleSheet } from 'react-native'; -import { button, buttonText, container, hr, link } from '../../constants'; +import { + button, + buttonText, + container, + hr, + link, + colors, +} from '../../constants'; const styles = StyleSheet.create({ button, @@ -26,6 +33,35 @@ const styles = StyleSheet.create({ utilitySection: { paddingHorizontal: 16, }, + viewTypeButton: { + alignItems: 'center', + borderColor: colors.brandCyan, + borderRadius: 8, + borderWidth: 2, + flex: 1, + paddingHorizontal: 12, + paddingVertical: 8, + }, + viewTypeButtonSelected: { + backgroundColor: colors.brandCyan, + }, + viewTypeButtonText: { + color: colors.brandCyan, + fontSize: 14, + fontWeight: '600', + }, + viewTypeButtonTextSelected: { + color: colors.backgroundPrimary, + }, + viewTypeButtons: { + flexDirection: 'row', + gap: 8, + justifyContent: 'space-around', + marginTop: 8, + }, + viewTypeSelector: { + marginVertical: 12, + }, }); export default styles; diff --git a/example/src/components/Embedded/Embedded.tsx b/example/src/components/Embedded/Embedded.tsx index 68b748048..1b0f8ce53 100644 --- a/example/src/components/Embedded/Embedded.tsx +++ b/example/src/components/Embedded/Embedded.tsx @@ -2,8 +2,10 @@ import { ScrollView, Text, TouchableOpacity, View } from 'react-native'; import { useCallback, useState } from 'react'; import { Iterable, - type IterableAction, + // type IterableAction, type IterableEmbeddedMessage, + IterableEmbeddedView, + IterableEmbeddedViewType, } from '@iterable/react-native-sdk'; import styles from './Embedded.styles'; @@ -13,6 +15,8 @@ export const Embedded = () => { const [embeddedMessages, setEmbeddedMessages] = useState< IterableEmbeddedMessage[] >([]); + const [selectedViewType, setSelectedViewType] = + useState(IterableEmbeddedViewType.Banner); const syncEmbeddedMessages = useCallback(() => { Iterable.embeddedManager.syncMessages(); @@ -49,52 +53,108 @@ export const Embedded = () => { }); }, [getPlacementIds]); - const startEmbeddedImpression = useCallback( - (message: IterableEmbeddedMessage) => { - console.log(`startEmbeddedImpression`, message); - Iterable.embeddedManager.startImpression( - message.metadata.messageId, - // TODO: check if this should be changed to a number, as per the type - Number(message.metadata.placementId) - ); - }, - [] - ); + // const startEmbeddedImpression = useCallback( + // (message: IterableEmbeddedMessage) => { + // console.log(`startEmbeddedImpression`, message); + // Iterable.embeddedManager.startImpression( + // message.metadata.messageId, + // // TODO: check if this should be changed to a number, as per the type + // Number(message.metadata.placementId) + // ); + // }, + // [] + // ); - const pauseEmbeddedImpression = useCallback( - (message: IterableEmbeddedMessage) => { - console.log(`pauseEmbeddedImpression:`, message); - Iterable.embeddedManager.pauseImpression(message.metadata.messageId); - }, - [] - ); + // const pauseEmbeddedImpression = useCallback( + // (message: IterableEmbeddedMessage) => { + // console.log(`pauseEmbeddedImpression:`, message); + // Iterable.embeddedManager.pauseImpression(message.metadata.messageId); + // }, + // [] + // ); - const handleClick = useCallback( - ( - message: IterableEmbeddedMessage, - buttonId: string | null, - action?: IterableAction | null - ) => { - console.log(`handleClick:`, message); - Iterable.embeddedManager.handleClick(message, buttonId, action); - }, - [] - ); + // const handleClick = useCallback( + // ( + // message: IterableEmbeddedMessage, + // buttonId: string | null, + // action?: IterableAction | null + // ) => { + // console.log(`handleClick:`, message); + // Iterable.embeddedManager.handleClick(message, buttonId, action); + // }, + // [] + // ); return ( EMBEDDED - - Does embedded class exist? {Iterable.embeddedManager ? 'Yes' : 'No'} - - - Is embedded manager enabled? - {Iterable.embeddedManager.isEnabled ? 'Yes' : 'No'} - Placement ids: [{placementIds.join(', ')}] + + Select View Type: + + + setSelectedViewType(IterableEmbeddedViewType.Banner) + } + > + + Banner + + + setSelectedViewType(IterableEmbeddedViewType.Card)} + > + + Card + + + + setSelectedViewType(IterableEmbeddedViewType.Notification) + } + > + + Notification + + + + Sync messages @@ -115,66 +175,11 @@ export const Embedded = () => { {embeddedMessages.map((message) => ( - - - Embedded message - - - startEmbeddedImpression(message)} - > - Start impression - - | - pauseEmbeddedImpression(message)} - > - Pause impression - - | - - handleClick(message, null, message.elements?.defaultAction) - } - > - Handle click - - - - metadata.messageId: {message.metadata.messageId} - metadata.placementId: {message.metadata.placementId} - elements.title: {message.elements?.title} - elements.body: {message.elements?.body} - - elements.defaultAction.data:{' '} - {message.elements?.defaultAction?.data} - - - elements.defaultAction.type:{' '} - {message.elements?.defaultAction?.type} - - {(message.elements?.buttons ?? []).map((button, buttonIndex) => ( - - - Button {buttonIndex + 1} - | - - handleClick(message, button.id, button.action) - } - > - Handle click - - - - button.id: {button.id} - button.title: {button.title} - button.action?.data: {button.action?.data} - button.action?.type: {button.action?.type} - - ))} - payload: {JSON.stringify(message.payload)} - + ))} diff --git a/src/embedded/components/IterableEmbeddedBanner.tsx b/src/embedded/components/IterableEmbeddedBanner.tsx new file mode 100644 index 000000000..56b4ca32b --- /dev/null +++ b/src/embedded/components/IterableEmbeddedBanner.tsx @@ -0,0 +1,19 @@ +import { View, Text } from 'react-native'; + +import type { IterableEmbeddedComponentProps } from '../types/IterableEmbeddedComponentProps'; + +export const IterableEmbeddedBanner = ({ + config, + message, + onButtonClick = () => {}, +}: IterableEmbeddedComponentProps) => { + console.log(`🚀 > IterableEmbeddedBanner > config:`, config); + console.log(`🚀 > IterableEmbeddedBanner > message:`, message); + console.log(`🚀 > IterableEmbeddedBanner > onButtonClick:`, onButtonClick); + + return ( + + IterableEmbeddedBanner + + ); +}; diff --git a/src/embedded/components/IterableEmbeddedCard.tsx b/src/embedded/components/IterableEmbeddedCard.tsx new file mode 100644 index 000000000..87b2d1940 --- /dev/null +++ b/src/embedded/components/IterableEmbeddedCard.tsx @@ -0,0 +1,18 @@ +import { View, Text } from 'react-native'; +import type { IterableEmbeddedComponentProps } from '../types/IterableEmbeddedComponentProps'; + +export const IterableEmbeddedCard = ({ + config, + message, + onButtonClick = () => {}, +}: IterableEmbeddedComponentProps) => { + console.log(`🚀 > IterableEmbeddedCard > config:`, config); + console.log(`🚀 > IterableEmbeddedCard > message:`, message); + console.log(`🚀 > IterableEmbeddedCard > onButtonClick:`, onButtonClick); + + return ( + + IterableEmbeddedCard + + ); +}; diff --git a/src/embedded/components/IterableEmbeddedNotification.tsx b/src/embedded/components/IterableEmbeddedNotification.tsx new file mode 100644 index 000000000..686ea01e6 --- /dev/null +++ b/src/embedded/components/IterableEmbeddedNotification.tsx @@ -0,0 +1,22 @@ +import { View, Text } from 'react-native'; + +import type { IterableEmbeddedComponentProps } from '../types/IterableEmbeddedComponentProps'; + +export const IterableEmbeddedNotification = ({ + config, + message, + onButtonClick = () => {}, +}: IterableEmbeddedComponentProps) => { + console.log(`🚀 > IterableEmbeddedNotification > config:`, config); + console.log(`🚀 > IterableEmbeddedNotification > message:`, message); + console.log( + `🚀 > IterableEmbeddedNotification > onButtonClick:`, + onButtonClick + ); + + return ( + + IterableEmbeddedNotification + + ); +}; diff --git a/src/embedded/components/IterableEmbeddedView.tsx b/src/embedded/components/IterableEmbeddedView.tsx new file mode 100644 index 000000000..fa76f584f --- /dev/null +++ b/src/embedded/components/IterableEmbeddedView.tsx @@ -0,0 +1,36 @@ +import { useMemo } from 'react'; + +import { IterableEmbeddedViewType } from '../enums/IterableEmbeddedViewType'; + +import { IterableEmbeddedBanner } from './IterableEmbeddedBanner'; +import { IterableEmbeddedCard } from './IterableEmbeddedCard'; +import { IterableEmbeddedNotification } from './IterableEmbeddedNotification'; +import type { IterableEmbeddedComponentProps } from '../types/IterableEmbeddedComponentProps'; + +/** + * The props for the IterableEmbeddedView component. + */ +interface IterableEmbeddedViewProps extends IterableEmbeddedComponentProps { + /** The type of view to render. */ + viewType: IterableEmbeddedViewType; +} + +export const IterableEmbeddedView = ({ + viewType, + ...props +}: IterableEmbeddedViewProps) => { + const Cmp = useMemo(() => { + switch (viewType) { + case IterableEmbeddedViewType.Card: + return IterableEmbeddedCard; + case IterableEmbeddedViewType.Notification: + return IterableEmbeddedNotification; + case IterableEmbeddedViewType.Banner: + return IterableEmbeddedBanner; + default: + return null; + } + }, [viewType]); + + return Cmp ? : null; +}; diff --git a/src/embedded/components/index.ts b/src/embedded/components/index.ts new file mode 100644 index 000000000..15af78aba --- /dev/null +++ b/src/embedded/components/index.ts @@ -0,0 +1,4 @@ +export * from './IterableEmbeddedBanner'; +export * from './IterableEmbeddedCard'; +export * from './IterableEmbeddedNotification'; +export * from './IterableEmbeddedView'; diff --git a/src/embedded/enums/IterableEmbeddedViewType.ts b/src/embedded/enums/IterableEmbeddedViewType.ts new file mode 100644 index 000000000..90a0b5d7e --- /dev/null +++ b/src/embedded/enums/IterableEmbeddedViewType.ts @@ -0,0 +1,11 @@ +/** + * The view type for an embedded message. + */ +export enum IterableEmbeddedViewType { + /** The embedded view is a banner */ + Banner = 0, + /** The embedded view is a card */ + Card = 1, + /** The embedded view is a notification */ + Notification = 2, +} diff --git a/src/embedded/enums/index.ts b/src/embedded/enums/index.ts new file mode 100644 index 000000000..511ad021b --- /dev/null +++ b/src/embedded/enums/index.ts @@ -0,0 +1 @@ +export * from './IterableEmbeddedViewType'; diff --git a/src/embedded/index.ts b/src/embedded/index.ts index 15eb796c9..967e49dbe 100644 --- a/src/embedded/index.ts +++ b/src/embedded/index.ts @@ -1,2 +1,4 @@ export * from './classes'; +export * from './components'; +export * from './enums'; export * from './types'; diff --git a/src/embedded/types/IterableEmbeddedComponentProps.ts b/src/embedded/types/IterableEmbeddedComponentProps.ts new file mode 100644 index 000000000..9f2b17670 --- /dev/null +++ b/src/embedded/types/IterableEmbeddedComponentProps.ts @@ -0,0 +1,9 @@ +import type { IterableEmbeddedMessage } from './IterableEmbeddedMessage'; +import type { IterableEmbeddedMessageElementsButton } from './IterableEmbeddedMessageElementsButton'; +import type { IterableEmbeddedViewConfig } from './IterableEmbeddedViewConfig'; + +export interface IterableEmbeddedComponentProps { + message: IterableEmbeddedMessage; + config?: IterableEmbeddedViewConfig | null; + onButtonClick?: (button: IterableEmbeddedMessageElementsButton) => void; +} diff --git a/src/embedded/types/IterableEmbeddedViewConfig.ts b/src/embedded/types/IterableEmbeddedViewConfig.ts new file mode 100644 index 000000000..6a41edd8a --- /dev/null +++ b/src/embedded/types/IterableEmbeddedViewConfig.ts @@ -0,0 +1,27 @@ +import type { ColorValue } from 'react-native'; + +/** + * Represents view-level styling configuration for an embedded view. + */ +export interface IterableEmbeddedViewConfig { + /** Background color hex (e.g., 0xFF0000) */ + backgroundColor?: ColorValue; + /** Border color hex */ + borderColor?: ColorValue; + /** Border width in pixels */ + borderWidth?: number; + /** Corner radius in points */ + borderCornerRadius?: number; + /** Primary button background color hex */ + primaryBtnBackgroundColor?: ColorValue; + /** Primary button text color hex */ + primaryBtnTextColor?: ColorValue; + /** Secondary button background color hex */ + secondaryBtnBackgroundColor?: ColorValue; + /** Secondary button text color hex */ + secondaryBtnTextColor?: ColorValue; + /** Title text color hex */ + titleTextColor?: ColorValue; + /** Body text color hex */ + bodyTextColor?: ColorValue; +} diff --git a/src/embedded/types/index.ts b/src/embedded/types/index.ts index 29b809ebf..66deee21e 100644 --- a/src/embedded/types/index.ts +++ b/src/embedded/types/index.ts @@ -1,5 +1,7 @@ +export * from './IterableEmbeddedComponentProps'; export * from './IterableEmbeddedMessage'; export * from './IterableEmbeddedMessageElements'; export * from './IterableEmbeddedMessageElementsButton'; export * from './IterableEmbeddedMessageElementsText'; export * from './IterableEmbeddedMessageMetadata'; +export * from './IterableEmbeddedViewConfig'; diff --git a/src/index.tsx b/src/index.tsx index 75c8489ec..b4ba8f5cf 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -32,6 +32,17 @@ export type { IterableEdgeInsetDetails, IterableRetryPolicy, } from './core/types'; +export { + IterableEmbeddedManager, + IterableEmbeddedView, + IterableEmbeddedViewType, + type IterableEmbeddedComponentProps, + type IterableEmbeddedMessage, + type IterableEmbeddedMessageElements, + type IterableEmbeddedMessageElementsButton, + type IterableEmbeddedMessageElementsText, + type IterableEmbeddedViewConfig, +} from './embedded'; export { IterableHtmlInAppContent, IterableInAppCloseSource, @@ -59,7 +70,3 @@ export { type IterableInboxProps, type IterableInboxRowViewModel, } from './inbox'; -export { - IterableEmbeddedManager, - type IterableEmbeddedMessage, -} from './embedded';