Skip to content

Commit a22a039

Browse files
committed
refactor: replace IterableEmbeddedBanner component with a new implementation and add styles
1 parent 7278e0c commit a22a039

4 files changed

Lines changed: 214 additions & 19 deletions

File tree

src/embedded/components/IterableEmbeddedBanner.tsx

Lines changed: 0 additions & 19 deletions
This file was deleted.
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import { StyleSheet, Platform } from 'react-native';
2+
3+
// See https://support.iterable.com/hc/en-us/articles/23230946708244-Out-of-the-Box-Views-for-Embedded-Messages#banners
4+
export const IMAGE_HEIGHT = Platform.OS === 'android' ? 80 : 100;
5+
export const IMAGE_WIDTH = Platform.OS === 'android' ? 80 : 100;
6+
7+
export const styles = StyleSheet.create({
8+
body: {
9+
alignSelf: 'stretch',
10+
fontSize: 14,
11+
fontWeight: '400',
12+
lineHeight: 20,
13+
},
14+
bodyContainer: {
15+
alignItems: 'center',
16+
alignSelf: 'stretch',
17+
display: 'flex',
18+
flexDirection: 'row',
19+
paddingTop: 4,
20+
},
21+
button: {
22+
borderRadius: 32,
23+
gap: 8,
24+
},
25+
buttonContainer: {
26+
alignItems: 'flex-start',
27+
alignSelf: 'stretch',
28+
display: 'flex',
29+
flexDirection: 'row',
30+
gap: 12,
31+
width: '100%',
32+
},
33+
buttonText: {
34+
fontSize: 14,
35+
fontWeight: '400',
36+
lineHeight: 20,
37+
paddingHorizontal: 12,
38+
paddingVertical: 8,
39+
},
40+
container: {
41+
alignItems: 'flex-start',
42+
borderStyle: 'solid',
43+
boxShadow:
44+
'0 1px 1px 0 rgba(0, 0, 0, 0.06), 0 0 2px 0 rgba(0, 0, 0, 0.06), 0 0 1px 0 rgba(0, 0, 0, 0.08)',
45+
display: 'flex',
46+
flexDirection: 'column',
47+
gap: 16,
48+
justifyContent: 'center',
49+
padding: 16,
50+
width: '100%',
51+
},
52+
mediaContainer: {
53+
alignItems: 'flex-start',
54+
alignSelf: 'stretch',
55+
display: 'flex',
56+
flexDirection: 'row',
57+
},
58+
mediaImage: {
59+
borderRadius: 6,
60+
borderStyle: 'solid',
61+
borderWidth: 1,
62+
height: IMAGE_HEIGHT,
63+
paddingHorizontal: 0,
64+
paddingVertical: 0,
65+
width: IMAGE_WIDTH,
66+
},
67+
textContainer: {
68+
alignSelf: 'center',
69+
display: 'flex',
70+
flexDirection: 'column',
71+
flexGrow: 1,
72+
flexShrink: 1,
73+
gap: 4,
74+
width: '100%',
75+
},
76+
title: {
77+
fontSize: 16,
78+
fontWeight: '700',
79+
lineHeight: 16,
80+
paddingBottom: 4,
81+
},
82+
});
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
import {
2+
Image,
3+
Text,
4+
TouchableOpacity,
5+
View,
6+
type TextStyle,
7+
type ViewStyle,
8+
PixelRatio,
9+
Pressable,
10+
} from 'react-native';
11+
12+
import { IterableEmbeddedViewType } from '../../enums';
13+
import { useEmbeddedView } from '../../hooks/useEmbeddedView';
14+
import type { IterableEmbeddedComponentProps } from '../../types/IterableEmbeddedComponentProps';
15+
import {
16+
styles,
17+
IMAGE_HEIGHT,
18+
IMAGE_WIDTH,
19+
} from './IterableEmbeddedBanner.styles';
20+
21+
/**
22+
* TODO: figure out how default action works.
23+
*/
24+
25+
export const IterableEmbeddedBanner = ({
26+
config,
27+
message,
28+
onButtonClick = () => {},
29+
onMessageClick = () => {},
30+
}: IterableEmbeddedComponentProps) => {
31+
const { parsedStyles, media, handleButtonClick, handleMessageClick } =
32+
useEmbeddedView(IterableEmbeddedViewType.Banner, {
33+
message,
34+
config,
35+
onButtonClick,
36+
onMessageClick,
37+
});
38+
39+
const buttons = message.elements?.buttons ?? [];
40+
41+
return (
42+
<Pressable onPress={() => handleMessageClick()}>
43+
<View
44+
style={[
45+
styles.container,
46+
{
47+
backgroundColor: parsedStyles.backgroundColor,
48+
borderColor: parsedStyles.borderColor,
49+
borderRadius: parsedStyles.borderCornerRadius,
50+
borderWidth: parsedStyles.borderWidth,
51+
} as ViewStyle,
52+
]}
53+
>
54+
{}
55+
<View
56+
// eslint-disable-next-line react-native/no-inline-styles
57+
style={[styles.bodyContainer, { gap: media.shouldShow ? 16 : 0 }]}
58+
>
59+
<View style={styles.textContainer}>
60+
<Text
61+
style={[
62+
styles.title,
63+
{ color: parsedStyles.titleTextColor } as TextStyle,
64+
]}
65+
>
66+
{message.elements?.title}
67+
</Text>
68+
<Text
69+
style={[
70+
styles.body,
71+
{ color: parsedStyles.bodyTextColor } as TextStyle,
72+
]}
73+
>
74+
{message.elements?.body}
75+
</Text>
76+
</View>
77+
{media.shouldShow && (
78+
<View style={styles.mediaContainer}>
79+
<Image
80+
source={{
81+
uri: media.url as string,
82+
width: PixelRatio.getPixelSizeForLayoutSize(IMAGE_WIDTH),
83+
height: PixelRatio.getPixelSizeForLayoutSize(IMAGE_HEIGHT),
84+
}}
85+
style={[
86+
styles.mediaImage,
87+
{
88+
backgroundColor: parsedStyles.backgroundColor,
89+
borderColor: parsedStyles.borderColor,
90+
},
91+
]}
92+
alt={media.caption as string}
93+
/>
94+
</View>
95+
)}
96+
</View>
97+
{buttons.length > 0 && (
98+
<View style={styles.buttonContainer}>
99+
{buttons.map((button, index) => {
100+
const backgroundColor =
101+
index === 0
102+
? parsedStyles.primaryBtnBackgroundColor
103+
: parsedStyles.secondaryBtnBackgroundColor;
104+
const textColor =
105+
index === 0
106+
? parsedStyles.primaryBtnTextColor
107+
: parsedStyles.secondaryBtnTextColor;
108+
return (
109+
<TouchableOpacity
110+
style={[styles.button, { backgroundColor } as ViewStyle]}
111+
onPress={() => handleButtonClick(button)}
112+
key={button.id}
113+
>
114+
<Text
115+
style={[
116+
styles.buttonText,
117+
{ color: textColor } as TextStyle,
118+
]}
119+
>
120+
{button.title}
121+
</Text>
122+
</TouchableOpacity>
123+
);
124+
})}
125+
</View>
126+
)}
127+
</View>
128+
</Pressable>
129+
);
130+
};
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './IterableEmbeddedBanner';
2+
export { IterableEmbeddedBanner as default } from './IterableEmbeddedBanner';

0 commit comments

Comments
 (0)