Skip to content

Commit e4464a1

Browse files
authored
Merge pull request #591 from Iterable/2.0.0-alpha/MOB-10033-add-inbox
[MOB-10033] Example App: inbox
2 parents 38db7c3 + 2a639ad commit e4464a1

File tree

12 files changed

+175
-10
lines changed

12 files changed

+175
-10
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Route } from '../../constants';
22

33
export const routeIcon = {
4+
[Route.Inbox]: 'mail-outline',
45
[Route.User]: 'person-outline',
56
};

example/src/components/App/Main.tsx

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,42 @@
11
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
2+
import { useState, useEffect } from 'react';
3+
4+
import { Iterable } from '@iterable/react-native-sdk';
25

36
import { colors, Route } from '../../constants';
47
import type { MainScreenParamList } from '../../types';
58
import { routeIcon } from './App.constants';
69
import { getIcon } from './App.utils';
710
import { User } from '../User';
11+
import Inbox from '../Inbox';
12+
import { useIterableApp } from '../../hooks';
813

914
const Tab = createBottomTabNavigator<MainScreenParamList>();
1015

1116
export const Main = () => {
17+
const {
18+
isInboxTab,
19+
isLoggedIn,
20+
loginInProgress,
21+
returnToInboxTrigger,
22+
setIsInboxTab,
23+
setReturnToInboxTrigger,
24+
userId,
25+
} = useIterableApp();
26+
const [unreadMessageCount, setUnreadMessageCount] = useState<number>(0);
27+
28+
useEffect(() => {
29+
if (loginInProgress) return;
30+
if (isLoggedIn) {
31+
Iterable.inAppManager.getMessages().then((messages) => {
32+
setUnreadMessageCount(messages.length);
33+
});
34+
} else {
35+
// Reset unread message count when user logs out
36+
setUnreadMessageCount(0);
37+
}
38+
}, [isLoggedIn, loginInProgress, userId]);
39+
1240
return (
1341
<>
1442
<Tab.Navigator
@@ -22,7 +50,28 @@ export const Main = () => {
2250
};
2351
}}
2452
>
25-
<Tab.Screen name={Route.User} component={User} />
53+
<Tab.Screen
54+
name={Route.Inbox}
55+
component={Inbox}
56+
options={
57+
unreadMessageCount ? { tabBarBadge: unreadMessageCount } : {}
58+
}
59+
listeners={() => ({
60+
tabPress: () => {
61+
if (isInboxTab) {
62+
setReturnToInboxTrigger(!returnToInboxTrigger);
63+
}
64+
setIsInboxTab(true);
65+
},
66+
})}
67+
/>
68+
<Tab.Screen
69+
name={Route.User}
70+
component={User}
71+
listeners={() => ({
72+
tabPress: () => setIsInboxTab(false),
73+
})}
74+
/>
2675
</Tab.Navigator>
2776
</>
2877
);
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
export const iterableInboxCustomization = {
2+
navTitle: 'Iterable',
3+
noMessagesTitle: 'No messages today',
4+
noMessagesBody: 'Come back later',
5+
6+
unreadIndicatorContainer: {
7+
flexDirection: 'column',
8+
justifyContent: 'flex-start',
9+
},
10+
11+
unreadIndicator: {
12+
width: 15,
13+
height: 15,
14+
borderRadius: 15 / 2,
15+
backgroundColor: 'orange',
16+
marginLeft: 10,
17+
marginRight: 10,
18+
marginTop: 10,
19+
},
20+
21+
unreadMessageIconContainer: {
22+
paddingLeft: 0,
23+
flexDirection: 'column',
24+
justifyContent: 'center',
25+
},
26+
27+
readMessageIconContainer: {
28+
paddingLeft: 35,
29+
flexDirection: 'column',
30+
justifyContent: 'center',
31+
},
32+
33+
messageContainer: {
34+
paddingLeft: 10,
35+
width: '65%',
36+
flexDirection: 'column',
37+
justifyContent: 'center',
38+
},
39+
40+
title: {
41+
fontSize: 22,
42+
paddingBottom: 10,
43+
},
44+
45+
body: {
46+
fontSize: 15,
47+
color: 'lightgray',
48+
width: '65%',
49+
flexWrap: 'wrap',
50+
paddingBottom: 10,
51+
},
52+
53+
createdAt: {
54+
fontSize: 12,
55+
color: 'lightgray',
56+
},
57+
58+
messageRow: {
59+
flexDirection: 'row',
60+
backgroundColor: 'white',
61+
paddingTop: 10,
62+
paddingBottom: 10,
63+
height: 200,
64+
borderStyle: 'solid',
65+
borderColor: 'red',
66+
borderTopWidth: 1,
67+
},
68+
};
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import {
2+
IterableInbox,
3+
type IterableInboxProps,
4+
} from '@iterable/react-native-sdk';
5+
6+
import { useIterableApp } from '../../hooks';
7+
import { iterableInboxCustomization } from './Inbox.constants';
8+
9+
export const Inbox = (props: IterableInboxProps) => {
10+
const { returnToInboxTrigger } = useIterableApp();
11+
12+
return (
13+
<IterableInbox
14+
returnToInboxTrigger={returnToInboxTrigger}
15+
customizations={iterableInboxCustomization}
16+
{...props}
17+
/>
18+
);
19+
};
20+
21+
export default Inbox;
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './Inbox';
2+
export { default } from './Inbox';

example/src/constants/routes.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export enum Route {
2+
Inbox = 'Inbox',
23
Login = 'Login',
34
Main = 'Main',
45
User = 'User',

example/src/hooks/useIterableApp.tsx

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ interface IterableAppProps {
3434
initialize: (navigation: Navigation) => void;
3535
/** Whether the SDK has been initialized */
3636
isInitialized?: boolean;
37+
/** Is the tab in focus the `Inbox` tab? */
38+
isInboxTab: boolean;
3739
/** Whether the user is logged in */
3840
isLoggedIn?: boolean;
3941
/**
@@ -45,10 +47,16 @@ interface IterableAppProps {
4547
loginInProgress?: boolean;
4648
/** Logs the user out */
4749
logout: () => void;
50+
/** TODO: Ask @evantk91 or @Ayyanchira what this is for */
51+
returnToInboxTrigger: boolean;
4852
/** Sets the API key for the user */
4953
setApiKey: (value: string) => void;
54+
/** Sets whether the tab in focus is the `Inbox` tab */
55+
setIsInboxTab: (value: boolean) => void;
5056
/** Sets whether the login is in progress */
5157
setLoginInProgress: (value: boolean) => void;
58+
/** TODO: Ask @evantk91 or @Ayyanchira what this is for */
59+
setReturnToInboxTrigger: (value: boolean) => void;
5260
/** Sets the user ID for the user */
5361
setUserId: (value: string) => void;
5462
/** The user ID for the user */
@@ -59,13 +67,17 @@ const IterableAppContext = createContext<IterableAppProps>({
5967
apiKey: undefined,
6068
config: null,
6169
initialize: () => undefined,
70+
isInboxTab: false,
6271
isInitialized: false,
6372
isLoggedIn: false,
6473
login: () => undefined,
6574
loginInProgress: false,
6675
logout: () => undefined,
76+
returnToInboxTrigger: false,
6777
setApiKey: () => undefined,
78+
setIsInboxTab: () => undefined,
6879
setLoginInProgress: () => undefined,
80+
setReturnToInboxTrigger: () => undefined,
6981
setUserId: () => undefined,
7082
userId: undefined,
7183
});
@@ -75,6 +87,9 @@ const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
7587
export const IterableAppProvider: FunctionComponent<
7688
React.PropsWithChildren<unknown>
7789
> = ({ children }) => {
90+
const [returnToInboxTrigger, setReturnToInboxTrigger] =
91+
useState<boolean>(false);
92+
const [isInboxTab, setIsInboxTab] = useState<boolean>(false);
7893
const [itblConfig, setItblConfig] = useState<IterableConfig | null>(null);
7994
const [isLoggedIn, setIsLoggedIn] = useState<boolean>(false);
8095
const [isInitialized, setIsInitialized] = useState<boolean>(false);
@@ -110,7 +125,7 @@ export const IterableAppProvider: FunctionComponent<
110125
config.inAppDisplayInterval = 1.0; // Min gap between in-apps. No need to set this in production.
111126

112127
config.urlHandler = (url: string) => {
113-
const routeNames = [Route.User];
128+
const routeNames = [Route.Inbox, Route.User];
114129
for (const route of routeNames) {
115130
if (url.includes(route.toLowerCase())) {
116131
// TODO: Figure out typing for this
@@ -191,13 +206,17 @@ export const IterableAppProvider: FunctionComponent<
191206
apiKey,
192207
config: itblConfig,
193208
initialize,
209+
isInboxTab,
194210
isInitialized,
195211
isLoggedIn,
196212
login,
197213
loginInProgress,
198214
logout,
215+
returnToInboxTrigger,
199216
setApiKey,
217+
setIsInboxTab,
200218
setLoginInProgress,
219+
setReturnToInboxTrigger,
201220
setUserId,
202221
userId,
203222
}}

example/src/types/navigation.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import type { StackScreenProps } from '@react-navigation/stack';
88
import { Route } from '../constants/routes';
99

1010
export type MainScreenParamList = {
11+
[Route.Inbox]: undefined;
1112
[Route.User]: undefined;
1213
};
1314

src/IterableInbox.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,15 @@ const RNIterableAPI = NativeModules.RNIterableAPI;
3030
const RNEventEmitter = new NativeEventEmitter(RNIterableAPI);
3131

3232
// TODO: Comment
33-
type InboxProps = {
33+
export interface IterableInboxProps {
3434
returnToInboxTrigger?: boolean;
3535
messageListItemLayout?: Function;
3636
customizations?: IterableInboxCustomizations;
3737
tabBarHeight?: number;
3838
tabBarPadding?: number;
3939
safeAreaMode?: boolean;
4040
showNavTitle?: boolean;
41-
};
41+
}
4242

4343
// TODO: Comment
4444
export const IterableInbox = ({
@@ -49,7 +49,7 @@ export const IterableInbox = ({
4949
tabBarPadding = 20,
5050
safeAreaMode = true,
5151
showNavTitle = true,
52-
}: InboxProps) => {
52+
}: IterableInboxProps) => {
5353
const defaultInboxTitle = 'Inbox';
5454
const inboxDataModel = new IterableInboxDataModel();
5555

src/IterableInboxMessageDisplay.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ export const IterableInboxMessageDisplay = ({
213213
}}
214214
>
215215
<View style={returnButton}>
216-
<Icon name="ios-chevron-back" style={returnButtonIcon} />
216+
<Icon name="chevron-back-outline" style={returnButtonIcon} />
217217
<Text style={returnButtonText}>Inbox</Text>
218218
</View>
219219
</TouchableWithoutFeedback>

0 commit comments

Comments
 (0)