@trycourier/courier-react-native 2.0.0-beta2 → 2.0.0-beta3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/ios/CourierReactNativeModule.m +43 -4
  2. package/ios/CourierReactNativeModule.swift +87 -79
  3. package/ios/CourierReactNativeViewManager.m +1 -3
  4. package/ios/CourierReactNativeViewManager.swift +4 -17
  5. package/lib/commonjs/hooks/useCourier.js +224 -0
  6. package/lib/commonjs/hooks/useCourier.js.map +1 -0
  7. package/lib/commonjs/index.js +193 -12
  8. package/lib/commonjs/index.js.map +1 -1
  9. package/lib/commonjs/models/CourierAuthenticationListener.js +21 -0
  10. package/lib/commonjs/models/CourierAuthenticationListener.js.map +1 -0
  11. package/lib/commonjs/models/CourierPushListener.js +15 -0
  12. package/lib/commonjs/models/CourierPushListener.js.map +1 -0
  13. package/lib/commonjs/views/CourierInboxView.js +4 -2
  14. package/lib/commonjs/views/CourierInboxView.js.map +1 -1
  15. package/lib/module/hooks/useCourier.js +213 -0
  16. package/lib/module/hooks/useCourier.js.map +1 -0
  17. package/lib/module/index.js +166 -13
  18. package/lib/module/index.js.map +1 -1
  19. package/lib/module/models/CourierAuthenticationListener.js +13 -0
  20. package/lib/module/models/CourierAuthenticationListener.js.map +1 -0
  21. package/lib/module/models/CourierPushListener.js +8 -0
  22. package/lib/module/models/CourierPushListener.js.map +1 -0
  23. package/lib/module/views/CourierInboxView.js +4 -2
  24. package/lib/module/views/CourierInboxView.js.map +1 -1
  25. package/lib/typescript/hooks/useCourier.d.ts +52 -0
  26. package/lib/typescript/hooks/useCourier.d.ts.map +1 -0
  27. package/lib/typescript/index.d.ts +81 -1
  28. package/lib/typescript/index.d.ts.map +1 -1
  29. package/lib/typescript/models/CourierAuthenticationListener.d.ts +7 -0
  30. package/lib/typescript/models/CourierAuthenticationListener.d.ts.map +1 -0
  31. package/lib/typescript/models/CourierPushListener.d.ts +7 -0
  32. package/lib/typescript/models/CourierPushListener.d.ts.map +1 -0
  33. package/lib/typescript/views/CourierInboxView.d.ts +4 -2
  34. package/lib/typescript/views/CourierInboxView.d.ts.map +1 -1
  35. package/package.json +1 -1
  36. package/src/hooks/useCourier.tsx +291 -0
  37. package/src/index.tsx +185 -13
  38. package/src/models/CourierAuthenticationListener.tsx +19 -0
  39. package/src/models/CourierPushListener.tsx +13 -0
  40. package/src/views/CourierInboxView.tsx +5 -4
@@ -0,0 +1,291 @@
1
+ import React, { createContext, ReactNode, useContext, useEffect, useState } from 'react';
2
+ import { InboxMessage } from 'src/models/InboxMessage';
3
+ import Courier, { CourierPushListener, CourierInboxListener, CourierAuthenticationListener } from '..';
4
+
5
+ let authListener: CourierAuthenticationListener | undefined = undefined
6
+ let pushListener: CourierPushListener | undefined = undefined
7
+ let inboxListener: CourierInboxListener | undefined = undefined
8
+
9
+ interface CourierContextType {
10
+ auth?: {
11
+ isLoading: boolean;
12
+ error?: string;
13
+ userId?: string;
14
+ signIn: (props: { accessToken: string, clientKey?: string, userId: string }) => Promise<void>;
15
+ signOut: () => Promise<void>;
16
+ }
17
+ push?: {
18
+ delivered: any;
19
+ clicked: any;
20
+ tokens: {
21
+ apns?: string,
22
+ fcm?: string;
23
+ },
24
+ notificationPermissionStatus?: string;
25
+ requestNotificationPermission: () => Promise<void>;
26
+ }
27
+ inbox?: {
28
+ isLoading: boolean;
29
+ error?: string;
30
+ messages: InboxMessage[];
31
+ unreadMessageCount: number;
32
+ totalMessageCount: number;
33
+ canPaginate: boolean;
34
+ setPaginationLimit: (limit: number) => void;
35
+ fetchNextPageOfMessages: () => Promise<InboxMessage[]>;
36
+ refresh: () => Promise<void>;
37
+ isRefreshing: boolean;
38
+ readAllMessages: () => Promise<void>;
39
+ readMessage: (messageId: string) => Promise<void>;
40
+ unreadMessage: (messageId: string) => Promise<void>;
41
+ }
42
+ }
43
+
44
+ const CourierContext = createContext<CourierContextType | undefined>(undefined);
45
+
46
+ export const CourierProvider: React.FC<{ listeners: ('auth' | 'push' | 'inbox')[], children: ReactNode }> = ({ listeners, children }) => {
47
+
48
+ // Auth
49
+ const [auth_userId, auth_setUserId] = useState<string | undefined>(undefined);
50
+ const [auth_isLoading, auth_setIsLoading] = useState<boolean>(false);
51
+ const [auth_error, auth_setError] = useState<string | undefined>(undefined);
52
+
53
+ // Push
54
+ const [push_pushNotificationDelivered, inbox_setPushNotificationDelivered] = useState<any>(undefined);
55
+ const [push_pushNotificationClicked, inbox_setPushNotificationClicked] = useState<any>(undefined);
56
+ const [push_apnsToken, push_setApnsToken] = useState<string | undefined>(undefined);
57
+ const [push_fcmToken, push_setFcmToken] = useState<string | undefined>(undefined);
58
+ const [push_notificationPermission, push_setNotificationPermission] = useState<string | undefined>(undefined);
59
+
60
+ // Inbox
61
+ const [inbox_isLoading, inbox_setIsLoading] = useState<boolean>(false);
62
+ const [inbox_isRefreshing, inbox_setIsRefreshing] = useState<boolean>(false);
63
+ const [inbox_error, inbox_setError] = useState<string | undefined>(undefined);
64
+ const [inbox_messages, inbox_setMessages] = useState<InboxMessage[]>([]);
65
+ const [inbox_unreadMessageCount, inbox_setUnreadMessageCount] = useState<number>(0);
66
+ const [inbox_totalMessageCount, inbox_setTotalMessageCount] = useState<number>(0);
67
+ const [inbox_canPaginate, inbox_setCanPaginate] = useState<boolean>(false);
68
+
69
+ useEffect(() => {
70
+
71
+ // Get the initial values
72
+ const userId = Courier.shared.userId;
73
+ auth_setUserId(userId);
74
+
75
+ // Permissions
76
+ syncNotificationPermissions();
77
+
78
+ // Push tokens
79
+ syncTokens();
80
+
81
+ }, [])
82
+
83
+ useEffect(() => {
84
+
85
+ authListener?.remove();
86
+ pushListener?.remove();
87
+ inboxListener?.remove();
88
+
89
+ // Push
90
+ if (listeners.includes('auth')) {
91
+
92
+ authListener = Courier.shared.addAuthenticationListener({
93
+ onUserChanged: (userId) => {
94
+ auth_setUserId(userId);
95
+ }
96
+ })
97
+
98
+ }
99
+
100
+ // Push
101
+ if (listeners.includes('push')) {
102
+
103
+ pushListener = Courier.shared.addPushNotificationListener({
104
+ onPushNotificationDelivered: (push) => inbox_setPushNotificationDelivered(push),
105
+ onPushNotificationClicked: (push) => inbox_setPushNotificationClicked(push)
106
+ });
107
+
108
+ }
109
+
110
+ // Inbox
111
+ if (listeners.includes('inbox')) {
112
+
113
+ inboxListener = Courier.shared.addInboxListener({
114
+ onInitialLoad: () => {
115
+ inbox_setIsLoading(true);
116
+ inbox_setError(undefined);
117
+ },
118
+ onError: (error) => {
119
+ inbox_setIsLoading(false);
120
+ inbox_setError(error);
121
+ },
122
+ onMessagesChanged: (messages, unreadMessageCount, totalMessageCount, canPaginate) => {
123
+ inbox_setIsLoading(false);
124
+ inbox_setError(undefined);
125
+ inbox_setMessages(messages);
126
+ inbox_setUnreadMessageCount(unreadMessageCount);
127
+ inbox_setTotalMessageCount(totalMessageCount);
128
+ inbox_setCanPaginate(canPaginate);
129
+ }
130
+ });
131
+
132
+ }
133
+
134
+ return () => {
135
+ authListener?.remove();
136
+ pushListener?.remove();
137
+ inboxListener?.remove();
138
+ }
139
+
140
+ }, [listeners]);
141
+
142
+ const signIn = async (props: { accessToken: string, clientKey?: string, userId: string }): Promise<void> => {
143
+
144
+ auth_setIsLoading(true);
145
+ auth_setError(undefined);
146
+
147
+ try {
148
+ await Courier.shared.signIn(props)
149
+ } catch (error) {
150
+ auth_setError(error as string);
151
+ }
152
+
153
+ auth_setIsLoading(false);
154
+
155
+ };
156
+
157
+ const signOut = async (): Promise<void> => {
158
+
159
+ auth_setIsLoading(true);
160
+ auth_setError(undefined);
161
+
162
+ try {
163
+ await Courier.shared.signOut();
164
+ } catch (error) {
165
+ auth_setError(error as string);
166
+ }
167
+
168
+ auth_setIsLoading(false);
169
+
170
+ };
171
+
172
+ const syncNotificationPermissions = async () => {
173
+
174
+ const status = await Courier.shared.getNotificationPermissionStatus();
175
+ push_setNotificationPermission(status);
176
+
177
+ }
178
+
179
+ const syncTokens = () => {
180
+
181
+ // APNS
182
+ const apnsToken = Courier.shared.apnsToken;
183
+ push_setApnsToken(apnsToken);
184
+
185
+ const fcmToken = Courier.shared.fcmToken;
186
+ push_setFcmToken(fcmToken);
187
+
188
+ }
189
+
190
+ const requestNotificationPermission = async () => {
191
+ const status = await Courier.shared.requestNotificationPermission();
192
+ push_setNotificationPermission(status);
193
+ };
194
+
195
+ const setPaginationLimit = (limit: number) => {
196
+ Courier.shared.setInboxPaginationLimit({ limit });
197
+ };
198
+
199
+ const fetchNextPageOfMessages = (): Promise<InboxMessage[]> => {
200
+ return Courier.shared.fetchNextPageOfMessages();
201
+ };
202
+
203
+ const refresh = async () => {
204
+ inbox_setIsRefreshing(true);
205
+ await Courier.shared.refreshInbox();
206
+ inbox_setIsRefreshing(false);
207
+ };
208
+
209
+ const readAllMessages = () => {
210
+
211
+ // Skip if no user is found
212
+ if (!Courier.shared.userId) {
213
+ return Promise.resolve();
214
+ }
215
+
216
+ // Read the messages
217
+ return Courier.shared.readAllInboxMessages();
218
+
219
+ };
220
+
221
+ const readMessage = (messageId: string) => {
222
+ return Courier.shared.readMessage({ messageId });
223
+ };
224
+
225
+ const unreadMessage = (messageId: string) => {
226
+ return Courier.shared.unreadMessage({ messageId });
227
+ };
228
+
229
+ return (
230
+ <CourierContext.Provider value={{
231
+ auth: {
232
+ isLoading: auth_isLoading,
233
+ error: auth_error,
234
+ userId: auth_userId,
235
+ signIn,
236
+ signOut
237
+ },
238
+ push: {
239
+ delivered: push_pushNotificationDelivered,
240
+ clicked: push_pushNotificationClicked,
241
+ tokens: {
242
+ fcm: push_fcmToken,
243
+ apns: push_apnsToken,
244
+ },
245
+ notificationPermissionStatus: push_notificationPermission,
246
+ requestNotificationPermission,
247
+ },
248
+ inbox: {
249
+ isLoading: inbox_isLoading,
250
+ error: inbox_error,
251
+ messages: inbox_messages,
252
+ unreadMessageCount: inbox_unreadMessageCount,
253
+ totalMessageCount: inbox_totalMessageCount,
254
+ canPaginate: inbox_canPaginate,
255
+ setPaginationLimit,
256
+ fetchNextPageOfMessages,
257
+ refresh,
258
+ isRefreshing: inbox_isRefreshing,
259
+ readAllMessages,
260
+ readMessage,
261
+ unreadMessage,
262
+ }
263
+ }}>
264
+ {children}
265
+ </CourierContext.Provider>
266
+ );
267
+
268
+ };
269
+
270
+ interface UseCourierProps {
271
+ inbox?: {
272
+ paginationLimit?: number;
273
+ }
274
+ }
275
+
276
+ export const useCourier = (props: UseCourierProps = {}): CourierContextType => {
277
+
278
+ const context = useContext(CourierContext);
279
+
280
+ if (!context) {
281
+ throw new Error('useCourier must be used within an CourierProvider');
282
+ }
283
+
284
+ // Set the initial pagination limit if needed
285
+ if (props.inbox?.paginationLimit) {
286
+ context.inbox?.setPaginationLimit(props.inbox?.paginationLimit)
287
+ }
288
+
289
+ return context;
290
+
291
+ };
package/src/index.tsx CHANGED
@@ -3,11 +3,21 @@ import {
3
3
  NativeEventEmitter,
4
4
  EmitterSubscription,
5
5
  Platform,
6
+ DeviceEventEmitter,
6
7
  } from 'react-native';
7
8
 
9
+ // Imports
8
10
  import { CourierInboxListener } from './models/CourierInboxListener';
11
+ import { CourierPushListener } from './models/CourierPushListener';
12
+ import { CourierAuthenticationListener } from './models/CourierAuthenticationListener';
9
13
  import { InboxMessage } from './models/InboxMessage';
14
+
15
+ // Exports
10
16
  export { CourierInboxView } from './views/CourierInboxView';
17
+ export { CourierProvider, useCourier } from './hooks/useCourier';
18
+ export { CourierInboxListener } from './models/CourierInboxListener';
19
+ export { CourierPushListener } from './models/CourierPushListener';
20
+ export { CourierAuthenticationListener } from './models/CourierAuthenticationListener';
11
21
 
12
22
  const LINKING_ERROR =
13
23
  `The package '@trycourier/courier-react-native' doesn't seem to be linked. Make sure: \n\n` +
@@ -32,6 +42,9 @@ const CourierEventEmitter = new NativeEventEmitter(
32
42
 
33
43
  class Courier {
34
44
 
45
+ readonly PUSH_NOTIFICATION_CLICKED = 'pushNotificationClicked';
46
+ readonly PUSH_NOTIFICATION_DELIVERED = 'pushNotificationDelivered';
47
+
35
48
  private static _sharedInstance: Courier;
36
49
  private _isDebugging = false;
37
50
  private debugListener: EmitterSubscription | undefined;
@@ -57,16 +70,7 @@ class Courier {
57
70
 
58
71
  private async setDefaults() {
59
72
  this.setIsDebugging(__DEV__);
60
- // try {
61
- // await Promise.all([
62
- // this.setIsDebugging(__DEV__),
63
- // // this.iOSForegroundPresentationOptions({
64
- // // options: ['sound', 'badge', 'list', 'banner'],
65
- // // }),
66
- // ]);
67
- // } catch (error) {
68
- // console.log(error);
69
- // }
73
+ this.iOSForegroundPresentationOptions({ options: ['sound', 'badge', 'list', 'banner'] });
70
74
  }
71
75
 
72
76
  /**
@@ -99,12 +103,143 @@ class Courier {
99
103
  return this._isDebugging;
100
104
  }
101
105
 
106
+ /**
107
+ * TODO
108
+ * @param props
109
+ * @returns
110
+ */
111
+ public iOSForegroundPresentationOptions(props: { options: ('sound' | 'badge' | 'list' | 'banner')[] }): string {
112
+
113
+ // Only works on iOS
114
+ if (Platform.OS !== 'ios') return 'unsupported';
115
+
116
+ const normalizedParams = Array.from(new Set(props.options));
117
+ return CourierReactNativeModules.iOSForegroundPresentationOptions({
118
+ options: normalizedParams,
119
+ });
120
+
121
+ }
122
+
123
+ /**
124
+ * Sets the current Apple Push Notification Service (APNS) token
125
+ * using Courier token management apis
126
+ * @example const apnsToken = await Courier.apnsToken
127
+ */
128
+ get apnsToken(): string | undefined {
129
+ if (Platform.OS !== 'ios') return undefined;
130
+ return CourierReactNativeModules.getApnsToken();
131
+ }
132
+
133
+ /**
134
+ * Sets the current Firebase Cloud Messaging (FCM) token
135
+ * using Courier token management apis
136
+ * @example const fcmToken = await Courier.fcmToken
137
+ */
138
+ get fcmToken(): string | undefined {
139
+ return CourierReactNativeModules.getFcmToken();
140
+ }
141
+
142
+ /**
143
+ * Sets the current Firebase Cloud Messaging (FCM) token
144
+ * using Courier token management apis
145
+ * @example await setFcmToken('asdf...asdf')
146
+ */
147
+ public setFcmToken(props: { token: string }): Promise<void> {
148
+ return CourierReactNativeModules.setFcmToken(props.token);
149
+ }
150
+
151
+ /**
152
+ * Gets notification permission status at a system level.
153
+ * @example const permissionStatus = await Courier.getNotificationPermissionStatus()
154
+ */
155
+ public getNotificationPermissionStatus(): Promise<string> {
156
+ return CourierReactNativeModules.getNotificationPermissionStatus();
157
+ }
158
+
159
+ /**
160
+ * Requests notification permission status at a system level.
161
+ * Returns the string associated with the permission status.
162
+ * Will return the current status and will not present a popup
163
+ * if the user has already been asked for permission.
164
+ * @example const permissionStatus = await Courier.requestNotificationPermission()
165
+ */
166
+ public requestNotificationPermission(): Promise<string> {
167
+ return CourierReactNativeModules.requestNotificationPermission();
168
+ }
169
+
170
+ /**
171
+ * @example
172
+ TODO
173
+ * @returns function that can be used to unsubscribe from registered listeners
174
+ */
175
+ public addPushNotificationListener(props: { onPushNotificationClicked?: (push: any) => void, onPushNotificationDelivered?: (push: any) => void }): CourierPushListener {
176
+
177
+ const pushListener = new CourierPushListener();
178
+
179
+ if (Platform.OS === 'android') {
180
+
181
+ if (props.onPushNotificationClicked) {
182
+ pushListener.onNotificationClickedListener = DeviceEventEmitter.addListener(this.PUSH_NOTIFICATION_CLICKED, (event: any) => {
183
+ try {
184
+ props.onPushNotificationClicked!(JSON.parse(event));
185
+ } catch (error) {
186
+ console.log(error);
187
+ }
188
+ });
189
+ }
190
+
191
+ if (props.onPushNotificationDelivered) {
192
+ pushListener.onNotificationDeliveredListener = DeviceEventEmitter.addListener(this.PUSH_NOTIFICATION_DELIVERED, (event: any) => {
193
+ try {
194
+ props.onPushNotificationDelivered!(JSON.parse(event));
195
+ } catch (error) {
196
+ console.log(error);
197
+ }
198
+ });
199
+ }
200
+
201
+ }
202
+
203
+ if (Platform.OS === 'ios') {
204
+
205
+ if (props.onPushNotificationClicked) {
206
+ pushListener.onNotificationClickedListener = CourierEventEmitter.addListener(this.PUSH_NOTIFICATION_CLICKED, (event: any) => {
207
+ try {
208
+ props.onPushNotificationClicked!(JSON.parse(event));
209
+ } catch (error) {
210
+ console.log(error);
211
+ }
212
+ });
213
+ }
214
+
215
+ if (props.onPushNotificationDelivered) {
216
+ pushListener.onNotificationDeliveredListener = CourierEventEmitter.addListener(this.PUSH_NOTIFICATION_DELIVERED, (event: any) => {
217
+ try {
218
+ props.onPushNotificationDelivered!(JSON.parse(event));
219
+ } catch (error) {
220
+ console.log(error);
221
+ }
222
+ });
223
+ }
224
+
225
+ }
226
+
227
+ // When listener is registered
228
+ // Attempt to fetch the last message that was clicked
229
+ // This is needed for when the app is killed and the
230
+ // user launched the app by clicking on a notifications
231
+ CourierReactNativeModules.registerPushNotificationClickedOnKilledState();
232
+
233
+ return pushListener
234
+
235
+ }
236
+
102
237
  /**
103
238
  * Returns the current user id stored in local native storage
104
239
  * @example const userId = await Courier.userId
105
240
  */
106
- get userId(): Promise<string | undefined> {
107
- return CourierReactNativeModules.getUserId();
241
+ get userId(): string | undefined {
242
+ return CourierReactNativeModules.getUserId() ?? undefined
108
243
  }
109
244
 
110
245
  /**
@@ -127,6 +262,43 @@ class Courier {
127
262
  return CourierReactNativeModules.signIn(props.accessToken, props.clientKey ?? null, props.userId);
128
263
  }
129
264
 
265
+ /**
266
+ * TODO
267
+ * @param props
268
+ * @returns
269
+ */
270
+ public signOut(): Promise<void> {
271
+ return CourierReactNativeModules.signOut();
272
+ }
273
+
274
+ /**
275
+ * TODO
276
+ * @param props
277
+ * @returns
278
+ */
279
+ public addAuthenticationListener(props: { onUserChanged: (userId?: string) => void }): CourierAuthenticationListener {
280
+
281
+ const authListener = new CourierAuthenticationListener();
282
+
283
+ authListener.onUserChanged = CourierEventEmitter.addListener('courierAuthUserChanged', event => {
284
+ props.onUserChanged(event)
285
+ });
286
+
287
+ authListener.listenerId = CourierReactNativeModules.addAuthenticationListener();
288
+
289
+ return authListener;
290
+
291
+ }
292
+
293
+ /**
294
+ * TODO
295
+ * @param props
296
+ * @returns
297
+ */
298
+ public removeAuthenticationListener(props: { listenerId: string }): string {
299
+ return CourierReactNativeModules.removeAuthenticationListener(props.listenerId);
300
+ }
301
+
130
302
  /**
131
303
  * TODO
132
304
  * @param props
@@ -187,7 +359,7 @@ class Courier {
187
359
  });
188
360
  }
189
361
 
190
- inboxListener.listenerId = CourierReactNativeModules.addInboxListener(null);
362
+ inboxListener.listenerId = CourierReactNativeModules.addInboxListener();
191
363
 
192
364
  return inboxListener;
193
365
 
@@ -0,0 +1,19 @@
1
+ import { EmitterSubscription } from "react-native";
2
+ import Courier from "..";
3
+
4
+ export class CourierAuthenticationListener {
5
+
6
+ public listenerId?: string
7
+ public onUserChanged?: EmitterSubscription
8
+
9
+ public remove() {
10
+
11
+ if (this.listenerId) {
12
+ Courier.shared.removeInboxListener({ listenerId: this.listenerId });
13
+ }
14
+
15
+ this.onUserChanged?.remove();
16
+
17
+ }
18
+
19
+ }
@@ -0,0 +1,13 @@
1
+ import { EmitterSubscription } from "react-native";
2
+
3
+ export class CourierPushListener {
4
+
5
+ public onNotificationClickedListener?: EmitterSubscription
6
+ public onNotificationDeliveredListener?: EmitterSubscription
7
+
8
+ public remove() {
9
+ this.onNotificationClickedListener?.remove();
10
+ this.onNotificationDeliveredListener?.remove();
11
+ }
12
+
13
+ }
@@ -5,8 +5,10 @@ import { InboxAction } from "src/models/InboxAction";
5
5
  import { InboxMessage } from "src/models/InboxMessage";
6
6
 
7
7
  type CourierInboxViewProps = {
8
- lightTheme?: CourierInboxTheme;
9
- darkTheme?: CourierInboxTheme;
8
+ theme?: {
9
+ light?: CourierInboxTheme,
10
+ dark?: CourierInboxTheme
11
+ };
10
12
  onClickInboxMessageAtIndex?: (message: InboxMessage, index: number) => void;
11
13
  onClickInboxActionForMessageAtIndex?: (action: InboxAction, message: InboxMessage, index: number) => void;
12
14
  onScrollInbox?: (offsetY: number, offsetX: number) => void;
@@ -73,8 +75,7 @@ export const CourierInboxView = (props: CourierInboxViewProps) => {
73
75
 
74
76
  return (
75
77
  <CourierInbox
76
- lightTheme={props.lightTheme}
77
- darkTheme={props.darkTheme}
78
+ theme={props.theme ?? { light: undefined, dark: undefined }}
78
79
  onClickInboxMessageAtIndex={onClickInboxMessageAtIndex}
79
80
  onClickInboxActionForMessageAtIndex={onClickInboxActionForMessageAtIndex}
80
81
  onScrollInbox={onScrollInbox}