@trycourier/courier-react-native 5.4.2 → 5.5.0

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 (113) hide show
  1. package/android/build.gradle +2 -2
  2. package/android/src/main/java/com/courierreactnative/CourierSharedModule.kt +41 -42
  3. package/android/src/main/java/com/courierreactnative/Utils.kt +1 -1
  4. package/courier-react-native.podspec +1 -1
  5. package/ios/CourierReactNativeDelegate.m +12 -8
  6. package/ios/CourierReactNativeEventEmitter.swift +1 -1
  7. package/ios/CourierReactNativeModule.m +3 -5
  8. package/ios/CourierSharedModule.swift +88 -112
  9. package/lib/commonjs/index.js +75 -93
  10. package/lib/commonjs/index.js.map +1 -1
  11. package/lib/commonjs/models/CourierInboxListener.js +1 -0
  12. package/lib/commonjs/models/CourierInboxListener.js.map +1 -1
  13. package/lib/commonjs/models/InboxAction.js +22 -0
  14. package/lib/commonjs/models/InboxAction.js.map +1 -1
  15. package/lib/commonjs/models/InboxMessage.js +64 -0
  16. package/lib/commonjs/models/InboxMessage.js.map +1 -1
  17. package/lib/commonjs/models/InboxMessageEvent.js +2 -0
  18. package/lib/commonjs/models/InboxMessageEvent.js.map +1 -0
  19. package/lib/commonjs/views/CourierInboxView.js +6 -4
  20. package/lib/commonjs/views/CourierInboxView.js.map +1 -1
  21. package/lib/example/src/App.js +11 -0
  22. package/lib/example/src/Emitter.js +11 -0
  23. package/lib/example/src/Env.js +6 -0
  24. package/lib/example/src/Home.js +67 -0
  25. package/lib/example/src/Poke.js +75 -0
  26. package/lib/example/src/Tabs.js +36 -0
  27. package/lib/example/src/Utils.js +71 -0
  28. package/lib/example/src/pages/Auth.js +224 -0
  29. package/lib/example/src/pages/Inbox.js +38 -0
  30. package/lib/example/src/pages/Preferences.js +13 -0
  31. package/lib/example/src/pages/PreferencesStack.js +11 -0
  32. package/lib/example/src/pages/Push.js +93 -0
  33. package/lib/example/src/pages/Styles.js +26 -0
  34. package/lib/example/src/pages/Tests.js +1068 -0
  35. package/lib/example/src/pages/inbox/InboxCustom.js +141 -0
  36. package/lib/example/src/pages/inbox/InboxDefault.js +22 -0
  37. package/lib/example/src/pages/inbox/InboxStyled.js +220 -0
  38. package/lib/example/src/pages/preferences/PreferencesCustom.js +91 -0
  39. package/lib/example/src/pages/preferences/PreferencesDefault.js +17 -0
  40. package/lib/example/src/pages/preferences/PreferencesDetail.js +127 -0
  41. package/lib/example/src/pages/preferences/PreferencesStyled.js +110 -0
  42. package/lib/module/index.js +67 -90
  43. package/lib/module/index.js.map +1 -1
  44. package/lib/module/models/CourierInboxListener.js +1 -0
  45. package/lib/module/models/CourierInboxListener.js.map +1 -1
  46. package/lib/module/models/InboxAction.js +16 -1
  47. package/lib/module/models/InboxAction.js.map +1 -1
  48. package/lib/module/models/InboxMessage.js +61 -1
  49. package/lib/module/models/InboxMessage.js.map +1 -1
  50. package/lib/module/models/InboxMessageEvent.js +2 -0
  51. package/lib/module/models/InboxMessageEvent.js.map +1 -0
  52. package/lib/module/views/CourierInboxView.js +6 -4
  53. package/lib/module/views/CourierInboxView.js.map +1 -1
  54. package/lib/package.json +171 -0
  55. package/lib/src/Broadcaster.js +24 -0
  56. package/lib/src/Modules.js +26 -0
  57. package/lib/src/client/BrandClient.js +17 -0
  58. package/lib/src/client/ClientModule.js +14 -0
  59. package/lib/src/client/CourierClient.js +31 -0
  60. package/lib/src/client/InboxClient.js +99 -0
  61. package/lib/src/client/PreferenceClient.js +63 -0
  62. package/lib/src/client/TokenClient.js +27 -0
  63. package/lib/src/client/TrackingClient.js +17 -0
  64. package/lib/src/index.js +567 -0
  65. package/lib/src/models/Android_CourierSheet.js +1 -0
  66. package/lib/src/models/CourierAuthenticationListener.js +14 -0
  67. package/lib/src/models/CourierBrand.js +1 -0
  68. package/lib/src/models/CourierButton.js +1 -0
  69. package/lib/src/models/CourierDevice.js +1 -0
  70. package/lib/src/models/CourierFont.js +1 -0
  71. package/lib/src/models/CourierInboxListener.js +20 -0
  72. package/lib/src/models/CourierInboxMessages.js +1 -0
  73. package/lib/src/models/CourierInboxTheme.js +1 -0
  74. package/lib/src/models/CourierInfoViewStyle.js +1 -0
  75. package/lib/src/models/CourierPaging.js +1 -0
  76. package/lib/src/models/CourierPreferencesTheme.js +1 -0
  77. package/lib/src/models/CourierPushListener.js +14 -0
  78. package/lib/src/models/CourierPushProvider.js +8 -0
  79. package/lib/src/models/CourierTrackingEvent.js +8 -0
  80. package/lib/src/models/CourierUserPreferences.js +51 -0
  81. package/lib/src/models/InboxAction.js +1 -0
  82. package/lib/src/models/InboxMessage.js +1 -0
  83. package/lib/src/models/InboxMessageFeed.js +1 -0
  84. package/lib/src/models/InboxMessageSet.js +1 -0
  85. package/lib/src/models/iOS_CourierCell.js +1 -0
  86. package/lib/src/models/iOS_CourierSheet.js +1 -0
  87. package/lib/src/utils.js +27 -0
  88. package/lib/src/views/CourierInboxView.js +75 -0
  89. package/lib/src/views/CourierPreferencesView.js +33 -0
  90. package/lib/typescript/src/index.d.ts +16 -20
  91. package/lib/typescript/src/index.d.ts.map +1 -1
  92. package/lib/typescript/src/models/CourierInboxListener.d.ts +4 -7
  93. package/lib/typescript/src/models/CourierInboxListener.d.ts.map +1 -1
  94. package/lib/typescript/src/models/InboxAction.d.ts +8 -4
  95. package/lib/typescript/src/models/InboxAction.d.ts.map +1 -1
  96. package/lib/typescript/src/models/InboxMessage.d.ts +28 -14
  97. package/lib/typescript/src/models/InboxMessage.d.ts.map +1 -1
  98. package/lib/typescript/src/models/InboxMessageEvent.d.ts +2 -0
  99. package/lib/typescript/src/models/InboxMessageEvent.d.ts.map +1 -0
  100. package/lib/typescript/src/models/InboxMessageFeed.d.ts +1 -1
  101. package/lib/typescript/src/models/InboxMessageFeed.d.ts.map +1 -1
  102. package/package.json +3 -2
  103. package/src/index.tsx +61 -99
  104. package/src/models/CourierInboxListener.tsx +10 -13
  105. package/src/models/InboxAction.tsx +28 -4
  106. package/src/models/InboxMessage.tsx +102 -14
  107. package/src/models/InboxMessageEvent.tsx +1 -0
  108. package/src/models/InboxMessageFeed.tsx +1 -1
  109. package/src/views/CourierInboxView.tsx +4 -4
  110. package/ios/CourierReactNative.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
  111. package/ios/CourierReactNative.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
  112. package/ios/CourierReactNative.xcodeproj/project.xcworkspace/xcuserdata/mike.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  113. package/ios/CourierReactNative.xcodeproj/xcuserdata/mike.xcuserdatad/xcschemes/xcschememanagement.plist +0 -14
@@ -0,0 +1,67 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
3
+ import { Alert, Button } from 'react-native';
4
+ import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
5
+ import Auth from './pages/Auth';
6
+ import Push from './pages/Push';
7
+ import Inbox from './pages/Inbox';
8
+ import Courier from '@trycourier/courier-react-native';
9
+ import PreferencesStack from './pages/PreferencesStack';
10
+ import Tests from './pages/Tests';
11
+ const Tab = createBottomTabNavigator();
12
+ const Home = () => {
13
+ const [unreadCount, setUnreadCount] = useState(0);
14
+ useEffect(() => {
15
+ const setupInbox = async () => {
16
+ // Setup Push
17
+ Courier.setIOSForegroundPresentationOptions({ options: ['sound', 'badge', 'list', 'banner'] });
18
+ const pushListener = Courier.shared.addPushNotificationListener({
19
+ onPushNotificationClicked(push) {
20
+ console.log(push);
21
+ Alert.alert('👆 Push Notification Clicked', JSON.stringify(push));
22
+ },
23
+ onPushNotificationDelivered(push) {
24
+ console.log(push);
25
+ Alert.alert('📬 Push Notification Delivered', JSON.stringify(push));
26
+ }
27
+ });
28
+ // Setup Inbox
29
+ await Courier.shared.setInboxPaginationLimit(100);
30
+ const inboxListener = await Courier.shared.addInboxListener({
31
+ onUnreadCountChanged(unreadCount) {
32
+ setUnreadCount(unreadCount);
33
+ },
34
+ });
35
+ return { pushListener, inboxListener };
36
+ };
37
+ const listeners = setupInbox();
38
+ return () => {
39
+ listeners.then(({ pushListener, inboxListener }) => {
40
+ pushListener.remove();
41
+ inboxListener.remove();
42
+ });
43
+ };
44
+ }, []);
45
+ const inboxOptions = () => {
46
+ const badgeCount = () => {
47
+ return unreadCount > 0 ? unreadCount : undefined;
48
+ };
49
+ return {
50
+ headerRight: () => (React.createElement(Button, { onPress: () => Courier.shared.readAllInboxMessages(), title: "Read All" })),
51
+ tabBarBadge: badgeCount(),
52
+ tabBarIcon: ({ color, size }) => (React.createElement(MaterialCommunityIcons, { name: 'bell', color: color, size: size }))
53
+ };
54
+ };
55
+ const icon = (icon) => {
56
+ return {
57
+ tabBarIcon: ({ color, size }) => (React.createElement(MaterialCommunityIcons, { name: icon, color: color, size: size }))
58
+ };
59
+ };
60
+ return (React.createElement(Tab.Navigator, null,
61
+ React.createElement(Tab.Screen, { name: "Auth", component: Auth, options: icon('account-circle') }),
62
+ React.createElement(Tab.Screen, { name: "Push", component: Push, options: icon('message-badge') }),
63
+ React.createElement(Tab.Screen, { name: "Inbox", component: Inbox, options: inboxOptions() }),
64
+ React.createElement(Tab.Screen, { name: "Preferences", component: PreferencesStack, options: { ...icon('wrench'), headerShown: false } }),
65
+ React.createElement(Tab.Screen, { name: "Tests", component: Tests, options: icon('test-tube') })));
66
+ };
67
+ export default Home;
@@ -0,0 +1,75 @@
1
+ import React, { useState, useEffect, useMemo, createContext, useContext } from 'react';
2
+ import { View, StyleSheet, Animated, Easing } from 'react-native';
3
+ const PokeContext = createContext(undefined);
4
+ export const usePoke = () => {
5
+ const context = useContext(PokeContext);
6
+ if (!context) {
7
+ throw new Error('usePoke must be used within a PokeProvider');
8
+ }
9
+ return context;
10
+ };
11
+ export const Poke = ({ children, initialEnabled = true, initialIndicatorStyle, initialTouchTimeout = 150, }) => {
12
+ const [enabled, setEnabled] = useState(initialEnabled);
13
+ const [indicatorStyle, setIndicatorStyle] = useState(initialIndicatorStyle || {});
14
+ const [touchTimeout, setTouchTimeout] = useState(initialTouchTimeout);
15
+ const contextValue = useMemo(() => ({
16
+ setEnabled,
17
+ setIndicatorStyle,
18
+ setTouchTimeout,
19
+ }), []);
20
+ return (React.createElement(PokeContext.Provider, { value: contextValue },
21
+ React.createElement(TouchIndicator, { enabled: enabled, indicatorStyle: indicatorStyle, touchTimeout: touchTimeout }, children)));
22
+ };
23
+ const TouchIndicator = ({ children, indicatorStyle, enabled, touchTimeout }) => {
24
+ const [latestTouch, setLatestTouch] = useState(null);
25
+ const indicatorSize = indicatorStyle?.size || 50;
26
+ const indicatorColor = indicatorStyle?.color || 'rgba(0, 122, 255, 0.4)'; // Default blue color
27
+ useEffect(() => {
28
+ if (latestTouch) {
29
+ const timer = setTimeout(() => {
30
+ setLatestTouch(null);
31
+ }, touchTimeout);
32
+ return () => clearTimeout(timer);
33
+ }
34
+ return () => { }; // Add this line
35
+ }, [latestTouch, touchTimeout]);
36
+ const handleTouch = (event) => {
37
+ if (!enabled)
38
+ return;
39
+ const touch = event.nativeEvent.touches[0]; // Get only the latest touch
40
+ if (touch) {
41
+ const newTouch = {
42
+ id: `${touch.identifier}-${Date.now()}`,
43
+ x: touch.pageX,
44
+ y: touch.pageY,
45
+ timestamp: Date.now(),
46
+ animation: new Animated.Value(1),
47
+ };
48
+ Animated.timing(newTouch.animation, {
49
+ toValue: 0,
50
+ duration: touchTimeout,
51
+ useNativeDriver: true,
52
+ easing: Easing.out(Easing.cubic),
53
+ }).start();
54
+ setLatestTouch(newTouch);
55
+ }
56
+ };
57
+ const touchIndicatorStyle = useMemo(() => ({
58
+ position: 'absolute',
59
+ width: indicatorSize,
60
+ height: indicatorSize,
61
+ borderRadius: indicatorSize / 2,
62
+ backgroundColor: indicatorColor,
63
+ zIndex: 9999,
64
+ }), [indicatorSize, indicatorColor]);
65
+ return (React.createElement(View, { style: StyleSheet.absoluteFill, onTouchStart: handleTouch, onTouchMove: handleTouch, onTouchEnd: handleTouch },
66
+ children,
67
+ enabled && latestTouch && (React.createElement(Animated.View, { key: latestTouch.id, style: [
68
+ touchIndicatorStyle,
69
+ {
70
+ left: latestTouch.x - indicatorSize / 2,
71
+ top: latestTouch.y - indicatorSize / 2,
72
+ opacity: latestTouch.animation,
73
+ },
74
+ ] }))));
75
+ };
@@ -0,0 +1,36 @@
1
+ import React from "react";
2
+ import { StyleSheet, Text, TouchableOpacity, View } from "react-native";
3
+ export const Tab = ({ title, isSelected, onPress }) => (React.createElement(TouchableOpacity, { onPress: onPress, style: [styles.tabButton, isSelected && styles.selectedTabButton] },
4
+ React.createElement(Text, { style: [styles.tabText, isSelected && styles.selectedTabText] }, title)));
5
+ export const TabControl = ({ tabs, selectedTab, setSelectedTab }) => (React.createElement(View, { style: styles.segmentedControl }, tabs.map((tab) => (React.createElement(Tab, { key: tab.key, title: tab.title, isSelected: selectedTab === tab.key, onPress: () => setSelectedTab(tab.key) })))));
6
+ const styles = StyleSheet.create({
7
+ container: {
8
+ flex: 1,
9
+ },
10
+ segmentedControl: {
11
+ flexDirection: 'row',
12
+ justifyContent: 'space-around',
13
+ width: '100%',
14
+ },
15
+ content: {
16
+ flex: 1,
17
+ width: '100%',
18
+ height: '100%',
19
+ },
20
+ tabButton: {
21
+ padding: 16,
22
+ flex: 1,
23
+ alignItems: 'center',
24
+ borderBottomWidth: 2,
25
+ borderBottomColor: 'transparent',
26
+ },
27
+ selectedTabButton: {
28
+ borderBottomColor: 'blue',
29
+ },
30
+ tabText: {
31
+ color: 'black',
32
+ },
33
+ selectedTabText: {
34
+ fontWeight: 'bold',
35
+ },
36
+ });
@@ -0,0 +1,71 @@
1
+ export class ExampleServer {
2
+ static async generateJwt(props) {
3
+ return new Promise((resolve, reject) => {
4
+ const url = 'https://api.courier.com/auth/issue-token';
5
+ const request = {
6
+ method: 'POST',
7
+ headers: {
8
+ 'Content-Type': 'application/json',
9
+ 'Authorization': `Bearer ${props.authKey}`
10
+ },
11
+ body: JSON.stringify({
12
+ scope: `user_id:${props.userId} write:user-tokens inbox:read:messages inbox:write:events read:preferences write:preferences read:brands`,
13
+ expires_in: '2 days'
14
+ })
15
+ };
16
+ fetch(url, request)
17
+ .then(response => response.json())
18
+ .then((data) => {
19
+ resolve(data.token);
20
+ })
21
+ .catch(error => {
22
+ reject(error);
23
+ });
24
+ });
25
+ }
26
+ static async sendTest(props) {
27
+ const url = 'https://api.courier.com/send';
28
+ const headers = {
29
+ 'Content-Type': 'application/json',
30
+ 'Authorization': `Bearer ${props.authKey}`,
31
+ };
32
+ const body = JSON.stringify({
33
+ 'message': {
34
+ 'to': {
35
+ 'user_id': props.userId
36
+ },
37
+ 'content': {
38
+ 'title': props.title ?? 'Test',
39
+ 'body': props.body ?? 'Body',
40
+ },
41
+ 'routing': {
42
+ 'method': 'all',
43
+ 'channels': [props.channel],
44
+ },
45
+ },
46
+ });
47
+ const response = await fetch(url, {
48
+ method: 'POST',
49
+ headers: headers,
50
+ body: body,
51
+ });
52
+ if (response.status === 202) {
53
+ const json = await response.json();
54
+ return json['requestId'] ?? 'Error';
55
+ }
56
+ else {
57
+ throw new Error('Failed to send test message');
58
+ }
59
+ }
60
+ }
61
+ export class Utils {
62
+ static generateUUID() {
63
+ let uuid = '';
64
+ const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
65
+ const charactersLength = characters.length;
66
+ for (let i = 0; i < 16; i++) {
67
+ uuid += characters.charAt(Math.floor(Math.random() * charactersLength));
68
+ }
69
+ return uuid;
70
+ }
71
+ }
@@ -0,0 +1,224 @@
1
+ import Courier from "@trycourier/courier-react-native";
2
+ import React, { useEffect, useRef, useState } from "react";
3
+ import { ActivityIndicator, Button, Modal, Platform, StyleSheet, Text, TextInput, TouchableOpacity, View } from "react-native";
4
+ import Env from "../Env";
5
+ import { ExampleServer } from "../Utils";
6
+ import { usePoke } from '../Poke';
7
+ const Auth = () => {
8
+ const [isLoading, setIsLoading] = useState(false);
9
+ const [userId, setUserId] = useState();
10
+ const [tenantId, setTenantId] = useState();
11
+ useEffect(() => {
12
+ const initAuth = async () => {
13
+ const authListener = await Courier.shared.addAuthenticationListener({
14
+ onUserChanged: async (userId) => {
15
+ setUserId(userId);
16
+ setTenantId(await Courier.shared.getTenantId());
17
+ console.log(`User changed: ${userId}`);
18
+ console.log(`Tenant changed: ${await Courier.shared.getTenantId()}`);
19
+ }
20
+ });
21
+ const userId = await Courier.shared.getUserId();
22
+ const tenantId = await Courier.shared.getTenantId();
23
+ console.log(`Initial user: ${userId}`);
24
+ console.log(`Initial tenant: ${tenantId}`);
25
+ refreshJWT(userId, tenantId);
26
+ return authListener;
27
+ };
28
+ let listener;
29
+ initAuth().then(result => {
30
+ listener = result;
31
+ });
32
+ return () => {
33
+ if (listener) {
34
+ listener.remove();
35
+ }
36
+ };
37
+ }, []);
38
+ async function refreshJWT(userId, tenantId) {
39
+ console.log('Refreshing JWT');
40
+ if (!userId) {
41
+ console.log(`No user found`);
42
+ setIsLoading(false);
43
+ return;
44
+ }
45
+ setIsLoading(true);
46
+ try {
47
+ console.log(`User ID: ${userId}`);
48
+ await Courier.shared.signOut();
49
+ const token = await ExampleServer.generateJwt({
50
+ authKey: Env.authKey,
51
+ userId: userId,
52
+ });
53
+ console.log(`New token: ${token}`);
54
+ await Courier.shared.signIn({
55
+ accessToken: token,
56
+ userId: userId,
57
+ tenantId: tenantId,
58
+ });
59
+ }
60
+ catch (e) {
61
+ console.error(e);
62
+ }
63
+ setIsLoading(false);
64
+ }
65
+ async function signIn(userId, tenantId) {
66
+ console.log('Signing User In');
67
+ console.log(`User ID: ${userId}`);
68
+ console.log(`Tenant ID: ${tenantId}`);
69
+ setIsLoading(true);
70
+ try {
71
+ const token = await ExampleServer.generateJwt({
72
+ authKey: Env.authKey,
73
+ userId: userId,
74
+ });
75
+ console.log(`New token: ${token}`);
76
+ await Courier.shared.signIn({
77
+ accessToken: token,
78
+ userId: userId,
79
+ tenantId: tenantId.length ? tenantId : undefined
80
+ });
81
+ setUserId(await Courier.shared.getUserId());
82
+ setTenantId(await Courier.shared.getTenantId());
83
+ }
84
+ catch (e) {
85
+ console.error(e);
86
+ }
87
+ setIsLoading(false);
88
+ }
89
+ async function signOut() {
90
+ await Courier.shared.signOut();
91
+ setUserId(await Courier.shared.getUserId());
92
+ setTenantId(await Courier.shared.getTenantId());
93
+ }
94
+ const styles = StyleSheet.create({
95
+ container: {
96
+ flex: 1,
97
+ justifyContent: 'center',
98
+ alignItems: 'center',
99
+ },
100
+ text: {
101
+ marginBottom: 10,
102
+ fontFamily: Platform.select({
103
+ ios: 'Courier',
104
+ android: 'monospace',
105
+ default: 'monospace',
106
+ }),
107
+ fontSize: 16,
108
+ },
109
+ });
110
+ const AuthButton = (props) => {
111
+ const [modalVisible, setModalVisible] = useState(false);
112
+ const [userId, setUserId] = useState('');
113
+ const [tenantId, setTenantId] = useState('');
114
+ const inputRef = useRef(null);
115
+ const styles = StyleSheet.create({
116
+ button: {
117
+ backgroundColor: 'lightgray',
118
+ padding: 10,
119
+ borderRadius: 5,
120
+ },
121
+ buttonText: {
122
+ fontSize: 16,
123
+ fontFamily: Platform.select({
124
+ ios: 'Courier',
125
+ android: 'monospace',
126
+ default: 'monospace',
127
+ }),
128
+ },
129
+ modalContainer: {
130
+ flex: 1,
131
+ justifyContent: 'center',
132
+ alignItems: 'center',
133
+ backgroundColor: 'rgba(0, 0, 0, 0.5)',
134
+ },
135
+ modalContent: {
136
+ backgroundColor: 'white',
137
+ padding: 20,
138
+ borderRadius: 5,
139
+ elevation: 5,
140
+ minWidth: 300,
141
+ },
142
+ input: {
143
+ borderWidth: 1,
144
+ borderColor: 'gray',
145
+ borderRadius: 5,
146
+ padding: 10,
147
+ marginBottom: 10,
148
+ },
149
+ });
150
+ useEffect(() => {
151
+ if (modalVisible) {
152
+ inputRef.current.focus();
153
+ }
154
+ }, [modalVisible]);
155
+ const handleButtonPress = async () => {
156
+ if (await Courier.shared.getUserId()) {
157
+ await signOut();
158
+ }
159
+ else {
160
+ setModalVisible(true);
161
+ }
162
+ };
163
+ const handleModalClose = () => {
164
+ setModalVisible(false);
165
+ };
166
+ const handleUserIdInputChange = (text) => {
167
+ setUserId(text);
168
+ };
169
+ const handleTenantIdInputChange = (text) => {
170
+ setTenantId(text);
171
+ };
172
+ const handleSaveButtonPress = () => {
173
+ signIn(userId, tenantId);
174
+ setModalVisible(false);
175
+ };
176
+ return (React.createElement(React.Fragment, null,
177
+ React.createElement(Modal, { visible: modalVisible, animationType: "slide", transparent: true },
178
+ React.createElement(View, { style: styles.modalContainer },
179
+ React.createElement(View, { style: styles.modalContent },
180
+ React.createElement(Text, null, "Set Courier User Id:"),
181
+ React.createElement(TextInput, { ref: inputRef, style: styles.input, value: userId, autoCapitalize: "none", autoCorrect: false, onChangeText: handleUserIdInputChange }),
182
+ React.createElement(Text, null, "Set Tenant Id:"),
183
+ React.createElement(TextInput, { style: styles.input, value: tenantId, autoCapitalize: "none", autoCorrect: false, onChangeText: handleTenantIdInputChange }),
184
+ React.createElement(Button, { title: "Sign In", onPress: handleSaveButtonPress }),
185
+ React.createElement(Button, { title: "Cancel", onPress: handleModalClose })))),
186
+ React.createElement(TouchableOpacity, { style: styles.button, onPress: handleButtonPress },
187
+ React.createElement(Text, { style: styles.buttonText }, props.buttonText))));
188
+ };
189
+ const ToggleTouchesButton = () => {
190
+ const styles = StyleSheet.create({
191
+ button: {
192
+ backgroundColor: 'lightgray',
193
+ padding: 10,
194
+ borderRadius: 5,
195
+ marginTop: 10, // Add some space between buttons
196
+ },
197
+ buttonText: {
198
+ fontSize: 16,
199
+ fontFamily: Platform.select({
200
+ ios: 'Courier',
201
+ android: 'monospace',
202
+ default: 'monospace',
203
+ }),
204
+ },
205
+ });
206
+ const [enabled, setEnabledState] = useState(false);
207
+ const { setEnabled } = usePoke();
208
+ const handleToggle = () => {
209
+ const newEnabled = !enabled;
210
+ setEnabledState(newEnabled);
211
+ setEnabled(newEnabled);
212
+ };
213
+ return (React.createElement(TouchableOpacity, { style: styles.button, onPress: handleToggle },
214
+ React.createElement(Text, { style: styles.buttonText }, enabled ? 'Hide Touches' : 'Show Touches')));
215
+ };
216
+ return (React.createElement(View, { style: styles.container },
217
+ isLoading && (React.createElement(ActivityIndicator, { size: "small" })),
218
+ !isLoading && (React.createElement(React.Fragment, null,
219
+ userId && React.createElement(Text, { style: styles.text }, userId),
220
+ tenantId && React.createElement(Text, { style: styles.text }, tenantId),
221
+ React.createElement(AuthButton, { buttonText: userId ? 'Sign Out' : 'Sign In' }),
222
+ React.createElement(ToggleTouchesButton, null)))));
223
+ };
224
+ export default Auth;
@@ -0,0 +1,38 @@
1
+ import React, { useState } from 'react';
2
+ import { StyleSheet, View } from 'react-native';
3
+ import InboxDefault from './inbox/InboxDefault';
4
+ import InboxStyled from './inbox/InboxStyled';
5
+ import InboxCustom from './inbox/InboxCustom';
6
+ import { TabControl } from '../Tabs';
7
+ const tabs = [
8
+ { title: 'Default', key: 'Default' },
9
+ { title: 'Styled', key: 'Styled' },
10
+ { title: 'Custom', key: 'Custom' },
11
+ ];
12
+ const Inbox = () => {
13
+ const [selectedTab, setSelectedTab] = useState('Default');
14
+ const renderContent = () => {
15
+ switch (selectedTab) {
16
+ case 'Default':
17
+ return React.createElement(InboxDefault, null);
18
+ case 'Styled':
19
+ return React.createElement(InboxStyled, null);
20
+ case 'Custom':
21
+ return React.createElement(InboxCustom, null);
22
+ default:
23
+ return null;
24
+ }
25
+ };
26
+ return (React.createElement(View, { style: styles.container },
27
+ React.createElement(TabControl, { tabs: tabs, selectedTab: selectedTab, setSelectedTab: setSelectedTab }),
28
+ React.createElement(View, { style: styles.content }, renderContent())));
29
+ };
30
+ const styles = StyleSheet.create({
31
+ container: {
32
+ flex: 1,
33
+ },
34
+ content: {
35
+ flex: 1,
36
+ },
37
+ });
38
+ export default Inbox;
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+ import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs';
3
+ import PreferencesCustom from './preferences/PreferencesCustom';
4
+ import PreferencesDefault from './preferences/PreferencesDefault';
5
+ import PreferencesStyled from './preferences/PreferencesStyled';
6
+ const Tab = createMaterialTopTabNavigator();
7
+ const PreferencesTab = () => {
8
+ return (React.createElement(Tab.Navigator, null,
9
+ React.createElement(Tab.Screen, { name: "Default", component: PreferencesDefault }),
10
+ React.createElement(Tab.Screen, { name: "Styled", component: PreferencesStyled }),
11
+ React.createElement(Tab.Screen, { name: "Custom", component: PreferencesCustom })));
12
+ };
13
+ export default PreferencesTab;
@@ -0,0 +1,11 @@
1
+ import React from 'react';
2
+ import { createStackNavigator } from '@react-navigation/stack';
3
+ import Preferences from './Preferences';
4
+ import PreferencesDetail from './preferences/PreferencesDetail';
5
+ const Stack = createStackNavigator();
6
+ const PreferencesStack = () => {
7
+ return (React.createElement(Stack.Navigator, null,
8
+ React.createElement(Stack.Screen, { name: "PreferencesTab", component: Preferences }),
9
+ React.createElement(Stack.Screen, { name: "PreferencesDetail", component: PreferencesDetail })));
10
+ };
11
+ export default PreferencesStack;
@@ -0,0 +1,93 @@
1
+ import Courier, { CourierPushProvider } from '@trycourier/courier-react-native';
2
+ import React, { useEffect, useState } from 'react';
3
+ import { View, Text, StyleSheet, TouchableOpacity, Clipboard, ActivityIndicator, Platform } from 'react-native';
4
+ const Push = () => {
5
+ const [isLoading, setIsLoading] = useState(false);
6
+ const [tokens, setTokens] = useState(new Map());
7
+ useEffect(() => {
8
+ setExampleToken();
9
+ }, []);
10
+ const refreshTokens = async () => {
11
+ const tokensMap = await Courier.shared.getAllTokens();
12
+ setTokens(tokensMap);
13
+ };
14
+ const setExampleToken = async () => {
15
+ setIsLoading(true);
16
+ const requestStatus = await Courier.requestNotificationPermission();
17
+ console.log('Request Notification Status: ' + requestStatus);
18
+ console.log('Get Notification Status: ' + await Courier.getNotificationPermissionStatus());
19
+ // Example of setting an expo token
20
+ await Courier.shared.setTokenForProvider({
21
+ provider: CourierPushProvider.EXPO,
22
+ token: 'example_expo_token'
23
+ });
24
+ setIsLoading(false);
25
+ refreshTokens();
26
+ };
27
+ const styles = StyleSheet.create({
28
+ container: {
29
+ flex: 1,
30
+ gap: 20,
31
+ justifyContent: 'center',
32
+ alignItems: 'center',
33
+ padding: 20,
34
+ },
35
+ button: {
36
+ backgroundColor: 'lightgray',
37
+ padding: 10,
38
+ borderRadius: 5,
39
+ },
40
+ buttonText: {
41
+ fontSize: 16,
42
+ fontFamily: Platform.select({
43
+ ios: 'Courier',
44
+ android: 'monospace',
45
+ default: 'monospace',
46
+ }),
47
+ },
48
+ itemContainer: {
49
+ flexDirection: 'row',
50
+ justifyContent: 'space-between',
51
+ alignItems: 'center',
52
+ paddingVertical: 8,
53
+ },
54
+ keyText: {
55
+ flex: 1,
56
+ textAlign: 'left',
57
+ fontFamily: Platform.select({
58
+ ios: 'Courier',
59
+ android: 'monospace',
60
+ default: 'monospace',
61
+ }),
62
+ fontWeight: 'bold',
63
+ fontSize: 16,
64
+ },
65
+ valueText: {
66
+ flex: 1,
67
+ textAlign: 'right',
68
+ fontFamily: Platform.select({
69
+ ios: 'Courier',
70
+ android: 'monospace',
71
+ default: 'monospace',
72
+ }),
73
+ fontSize: 16,
74
+ },
75
+ });
76
+ const handleCopyToClipboard = (value) => {
77
+ Clipboard.setString(value);
78
+ };
79
+ const handleButtonPress = () => {
80
+ Courier.requestNotificationPermission();
81
+ };
82
+ return (React.createElement(View, { style: styles.container },
83
+ isLoading && (React.createElement(ActivityIndicator, { size: "small" })),
84
+ !isLoading && (React.createElement(React.Fragment, null,
85
+ Array.from(tokens).map(([key, value]) => (React.createElement(TouchableOpacity, { key: key, onPress: () => handleCopyToClipboard(value), style: styles.itemContainer },
86
+ React.createElement(Text, { style: styles.keyText }, key),
87
+ React.createElement(Text, { style: styles.valueText }, value)))),
88
+ React.createElement(TouchableOpacity, { style: styles.button, onPress: refreshTokens },
89
+ React.createElement(Text, { style: styles.buttonText }, "Refresh Tokens")),
90
+ React.createElement(TouchableOpacity, { style: styles.button, onPress: handleButtonPress },
91
+ React.createElement(Text, { style: styles.buttonText }, "Request Permissions"))))));
92
+ };
93
+ export default Push;
@@ -0,0 +1,26 @@
1
+ import { Platform } from "react-native";
2
+ export const Styles = (isDark) => {
3
+ return {
4
+ Fonts: {
5
+ heading: Platform.OS === 'ios' ? 'Avenir Medium' : 'fonts/poppins_regular.otf',
6
+ title: Platform.OS === 'ios' ? 'Avenir Medium' : 'fonts/poppins_regular.otf',
7
+ subtitle: Platform.OS === 'ios' ? 'Avenir Medium' : 'fonts/poppins_regular.otf'
8
+ },
9
+ Colors: {
10
+ heading: isDark ? '#9747FF' : '#9747FF',
11
+ title: isDark ? '#FFFFFF' : '#000000',
12
+ subtitle: isDark ? '#9A9A9A' : '#BEBEBE',
13
+ warning: isDark ? '#C32F27' : '#C32F27',
14
+ option: isDark ? '#1F1F1F' : '#F0F0F0',
15
+ action: isDark ? '#9747FF' : '#9747FF',
16
+ },
17
+ TextSizes: {
18
+ heading: 24,
19
+ title: 18,
20
+ subtitle: 16,
21
+ },
22
+ Corners: {
23
+ button: 100
24
+ }
25
+ };
26
+ };