Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion example/src/components/Embedded/Embedded.styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,13 @@ import {
container,
hr,
input,
modalButton,
modalButtons,
modalContent,
modalOverlay,
subtitle,
title,
utilityColors,
utilityColors
} from '../../constants';

const styles = StyleSheet.create({
Expand All @@ -26,6 +30,15 @@ const styles = StyleSheet.create({
inputContainer: {
marginVertical: 10,
},
jsonEditor: {
...input,
fontSize: 12,
height: 220,
},
modalButton,
modalButtons,
modalContent,
modalOverlay,
subtitle: { ...subtitle, textAlign: 'center' },
text: { textAlign: 'center' },
textInput: input,
Expand Down
69 changes: 69 additions & 0 deletions example/src/components/Embedded/Embedded.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import {
Alert,
Modal,
ScrollView,
Text,
TextInput,
Expand All @@ -9,20 +11,28 @@ import { useCallback, useState } from 'react';
import {
Iterable,
type IterableEmbeddedMessage,
type IterableEmbeddedViewConfig,
IterableEmbeddedView,
IterableEmbeddedViewType,
} from '@iterable/react-native-sdk';
import { SafeAreaView } from 'react-native-safe-area-context';

import styles from './Embedded.styles';

const DEFAULT_CONFIG_JSON = `{
}`;

export const Embedded = () => {
const [placementIdsInput, setPlacementIdsInput] = useState<string>('');
const [embeddedMessages, setEmbeddedMessages] = useState<
IterableEmbeddedMessage[]
>([]);
const [selectedViewType, setSelectedViewType] =
useState<IterableEmbeddedViewType>(IterableEmbeddedViewType.Banner);
const [viewConfig, setViewConfig] =
useState<IterableEmbeddedViewConfig | null>(null);
const [configEditorVisible, setConfigEditorVisible] = useState(false);
const [configJson, setConfigJson] = useState(DEFAULT_CONFIG_JSON);

// Parse placement IDs from input
const parsedPlacementIds = placementIdsInput
Expand Down Expand Up @@ -55,6 +65,27 @@ export const Embedded = () => {
});
}, [idsToFetch]);

const openConfigEditor = useCallback(() => {
setConfigJson(
viewConfig ? JSON.stringify(viewConfig, null, 2) : DEFAULT_CONFIG_JSON
);
setConfigEditorVisible(true);
}, [viewConfig]);

const applyConfig = useCallback(() => {
try {
const parsed = JSON.parse(configJson) as IterableEmbeddedViewConfig;
setViewConfig(parsed);
setConfigEditorVisible(false);
} catch {
Alert.alert('Error', 'Invalid JSON');
}
}, [configJson]);

const closeConfigEditor = useCallback(() => {
setConfigEditorVisible(false);
}, []);

return (
<SafeAreaView style={styles.container}>
<Text style={styles.title}>Embedded</Text>
Expand Down Expand Up @@ -142,6 +173,9 @@ export const Embedded = () => {
<TouchableOpacity style={styles.button} onPress={endEmbeddedSession}>
<Text style={styles.buttonText}>End session</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={openConfigEditor}>
<Text style={styles.buttonText}>Set view config</Text>
</TouchableOpacity>
<View style={styles.inputContainer}>
<Text style={styles.text}>Placement IDs (comma-separated):</Text>
<TextInput
Expand All @@ -159,6 +193,40 @@ export const Embedded = () => {
</TouchableOpacity>
</View>
</View>
<Modal
visible={configEditorVisible}
animationType="slide"
transparent
onRequestClose={closeConfigEditor}
>
<View style={styles.modalOverlay}>
<View style={styles.modalContent}>
<TextInput
style={styles.jsonEditor}
value={configJson}
onChangeText={setConfigJson}
multiline
textAlignVertical="top"
placeholder={DEFAULT_CONFIG_JSON}
placeholderTextColor="#999"
/>
<View style={styles.modalButtons}>
<TouchableOpacity
style={[styles.button, styles.modalButton]}
onPress={closeConfigEditor}
>
<Text style={styles.buttonText}>Cancel</Text>
</TouchableOpacity>
<TouchableOpacity
style={[styles.button, styles.modalButton]}
onPress={applyConfig}
>
<Text style={styles.buttonText}>Apply</Text>
</TouchableOpacity>
</View>
</View>
</View>
</Modal>
<View style={styles.hr} />
<ScrollView>
<View style={styles.embeddedSection}>
Expand All @@ -167,6 +235,7 @@ export const Embedded = () => {
key={message.metadata.messageId}
viewType={selectedViewType}
message={message}
config={viewConfig}
/>
))}
</View>
Expand Down
1 change: 1 addition & 0 deletions example/src/constants/styles/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ export * from './colors';
export * from './containers';
export * from './formElements';
export * from './miscElements';
export * from './modal';
export * from './shadows';
export * from './typography';
43 changes: 43 additions & 0 deletions example/src/constants/styles/modal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import type { TextStyle, ViewStyle } from "react-native";
import { colors } from "./colors";

export const modalTitle: TextStyle = {
fontSize: 18,
fontWeight: '600',
marginBottom: 12,
textAlign: 'center',
};

export const modalOverlay: ViewStyle = {
backgroundColor: 'rgba(0,0,0,0.5)',
flex: 1,
justifyContent: 'center',
padding: 20,
};

export const modalContent: ViewStyle = {
backgroundColor: colors.backgroundPrimary,
borderRadius: 12,
maxHeight: '80%',
padding: 16,
};

export const modalButtons: ViewStyle = {
flexDirection: 'row',
gap: 12,
justifyContent: 'flex-end',
};

export const modalButton: ViewStyle = {
flex: 1,
};

export const modalButtonText: TextStyle = {
color: colors.brandCyan,
fontSize: 14,
fontWeight: '600',
};

export const modalButtonTextSelected: TextStyle = {
color: colors.backgroundPrimary,
};
40 changes: 39 additions & 1 deletion src/embedded/components/IterableEmbeddedView.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { useMemo } from 'react';
import { View, Text } from 'react-native';

import { IterableEmbeddedViewType } from '../enums/IterableEmbeddedViewType';

import { IterableEmbeddedBanner } from './IterableEmbeddedBanner';
import { IterableEmbeddedCard } from './IterableEmbeddedCard';
import { IterableEmbeddedNotification } from './IterableEmbeddedNotification';
import type { IterableEmbeddedComponentProps } from '../types/IterableEmbeddedComponentProps';
import { useEmbeddedView } from '../hooks/useEmbeddedView/useEmbeddedView';

/**
* The props for the IterableEmbeddedView component.
Expand Down Expand Up @@ -43,5 +45,41 @@ export const IterableEmbeddedView = ({
}
}, [viewType]);

return Cmp ? <Cmp {...props} /> : null;
const { parsedStyles } = useEmbeddedView(viewType, props);

return Cmp ? (
<View>
<Text>
parsedStyles.backgroundColor: {String(parsedStyles.backgroundColor)}
</Text>
<Text>parsedStyles.borderColor: {String(parsedStyles.borderColor)}</Text>
<Text>parsedStyles.borderWidth: {parsedStyles.borderWidth}</Text>
<Text>
parsedStyles.borderCornerRadius: {parsedStyles.borderCornerRadius}
</Text>
<Text>
parsedStyles.primaryBtnBackgroundColor:{' '}
{String(parsedStyles.primaryBtnBackgroundColor)}
</Text>
<Text>
parsedStyles.primaryBtnTextColor:{' '}
{String(parsedStyles.primaryBtnTextColor)}
</Text>
<Text>
parsedStyles.secondaryBtnBackgroundColor:{' '}
{String(parsedStyles.secondaryBtnBackgroundColor)}
</Text>
<Text>
parsedStyles.secondaryBtnTextColor:{' '}
{String(parsedStyles.secondaryBtnTextColor)}
</Text>
<Text>
parsedStyles.titleTextColor: {String(parsedStyles.titleTextColor)}
</Text>
<Text>
parsedStyles.bodyTextColor: {String(parsedStyles.bodyTextColor)}
</Text>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocker: This entire debug block (lines 51-81) renders raw style values as <Text> nodes on screen, and wraps <Cmp> in an extra <View>. This looks like scaffolding/dev output and should be removed before merge.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just for demonstration and easy testing purposes. It will be removed in future PRs.

<Cmp {...props} />

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parsedStyles is computed but never passed to <Cmp>. The child components (Banner/Card/Notification) won't receive or apply these styles. Should this be something like <Cmp {...props} parsedStyles={parsedStyles} />?

Copy link
Contributor Author

@lposen lposen Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The whole function is going to go inside the other components in future PRs. This is just for making it easy to test.

</View>
) : null;
};
72 changes: 72 additions & 0 deletions src/embedded/constants/embeddedViewDefaults.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
export const embeddedBackgroundColors = {
notification: '#ffffff',
card: '#ffffff',
banner: '#ffffff',
};

export const embeddedBorderColors = {
notification: '#E0DEDF',
card: '#E0DEDF',
banner: '#E0DEDF',
};

export const embeddedPrimaryBtnBackgroundColors = {
notification: '#6A266D',
card: 'transparent',
banner: '#6A266D',
};

export const embeddedPrimaryBtnTextColors = {
notification: '#ffffff',
card: '#79347F',
banner: '#ffffff',
};

export const embeddedSecondaryBtnBackgroundColors = {
notification: 'transparent',
card: 'transparent',
banner: 'transparent',
};

export const embeddedSecondaryBtnTextColors = {
notification: '#79347F',
card: '#79347F',
banner: '#79347F',
};

export const embeddedTitleTextColors = {
notification: '#3D3A3B',
card: '#3D3A3B',
banner: '#3D3A3B',
};

export const embeddedBodyTextColors = {
notification: '#787174',
card: '#787174',
banner: '#787174',
};

export const embeddedBorderRadius = {
notification: 8,
card: 6,
banner: 8,
};

export const embeddedBorderWidth = {
notification: 1,
card: 1,
banner: 1,
};

export const embeddedStyles = {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

embeddedMediaImageBorderColors and embeddedMediaImageBackgroundColors are defined and added to embeddedStyles, but never consumed in getStyles.ts. Remove them or add the corresponding style resolution to avoid dead code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're 100% correct. Good eye. They ended up in here because I was breaking down a very large PR. I'll remove them and add them back in later when they are needed.

backgroundColor: embeddedBackgroundColors,
bodyText: embeddedBodyTextColors,
borderColor: embeddedBorderColors,
borderCornerRadius: embeddedBorderRadius,
borderWidth: embeddedBorderWidth,
primaryBtnBackgroundColor: embeddedPrimaryBtnBackgroundColors,
primaryBtnTextColor: embeddedPrimaryBtnTextColors,
secondaryBtnBackground: embeddedSecondaryBtnBackgroundColors,
secondaryBtnTextColor: embeddedSecondaryBtnTextColors,
titleText: embeddedTitleTextColors,
};
1 change: 1 addition & 0 deletions src/embedded/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './useEmbeddedView';
Loading