@onairos/react-native 3.0.29 → 3.0.30

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.
@@ -1,89 +1,183 @@
1
- import React, { useCallback, useState } from 'react';
2
- import { View, StyleSheet, ActivityIndicator, SafeAreaView, TouchableOpacity } from 'react-native';
3
- import { WebView, WebViewNavigation } from 'react-native-webview';
1
+ import React, { useState } from 'react';
2
+ import {
3
+ View,
4
+ Text,
5
+ StyleSheet,
6
+ TouchableOpacity,
7
+ ActivityIndicator,
8
+ SafeAreaView,
9
+ Dimensions,
10
+ } from 'react-native';
11
+ import { WebView } from 'react-native-webview';
4
12
  import Icon from 'react-native-vector-icons/MaterialIcons';
5
13
  import { COLORS } from '../../constants';
6
- import type { OAuthWebViewProps } from '../../types';
14
+
15
+ const { width, height } = Dimensions.get('window');
16
+
17
+ export interface OAuthWebViewProps {
18
+ url: string;
19
+ onClose: () => void;
20
+ onSuccess: (code: string) => void;
21
+ platform?: string;
22
+ onComplete?: () => void;
23
+ }
7
24
 
8
25
  export const OAuthWebView: React.FC<OAuthWebViewProps> = ({
9
26
  url,
10
- platform,
11
- onComplete,
12
27
  onClose,
13
28
  onSuccess,
29
+ platform = 'platform',
30
+ onComplete,
14
31
  }) => {
15
- const [loading, setLoading] = useState(true);
32
+ const [isLoading, setIsLoading] = useState(true);
33
+
34
+ console.log('Opening OAuth WebView with URL:', url); // Add logging
16
35
 
17
- const handleNavigationStateChange = useCallback(
18
- (navState: WebViewNavigation) => {
19
- console.log('Navigation state changed:', navState.url);
20
-
21
- // Check for the final redirect to onairos.uk/Home
22
- const isFinalRedirect = navState.url.includes('onairos.uk/Home');
23
-
24
- // Check for Instagram-specific success patterns
25
- const isInstagramSuccess = (
26
- platform === 'instagram' &&
27
- (navState.url.includes('instagram.com/oauth/authorize') ||
28
- navState.url.includes('instagram.com/accounts/login') ||
29
- navState.url.includes('code='))
30
- );
31
-
32
- // Check for platform-specific success patterns
33
- const isYouTubeSuccess = (
34
- platform === 'youtube' &&
35
- navState.url.includes('accounts.google.com/o/oauth2/approval')
36
- );
37
-
38
- const isLinkedInSuccess = (
39
- platform === 'linkedin' &&
40
- navState.url.includes('linkedin.com/oauth/v2/authorization/success')
41
- );
42
-
43
- // Check for callback URLs with authorization codes
44
- const isCallbackUrl = navState.url.includes('/callback') || navState.url.includes('code=');
45
-
46
- // If we detect success, close the window and update connection status
47
- if (isFinalRedirect || isInstagramSuccess || isYouTubeSuccess || isLinkedInSuccess) {
36
+ const handleNavigationStateChange = (navState: any) => {
37
+ console.log(`Navigation state changed for ${platform}:`, navState.url);
38
+
39
+ // Check for the final redirect to onairos.uk domain (this means backend callback completed)
40
+ const isFinalRedirect = (
41
+ navState.url.includes('onairos.uk/Home') ||
42
+ navState.url.includes('onairos.uk/home') ||
43
+ navState.url.includes('onairos.uk/success')
44
+ );
45
+
46
+ // For YouTube specifically, we need to be more careful about when to close
47
+ // Only close after the backend callback redirects to onairos.uk/Home
48
+ if (platform === 'youtube') {
49
+ // Only trigger success when we see the final redirect from the backend
50
+ if (isFinalRedirect) {
51
+ console.log('YouTube OAuth completed - backend callback finished and redirected to Home');
48
52
  onSuccess('success');
49
- if (onComplete) {
50
- onComplete();
51
- }
52
- return;
53
- } else if (isCallbackUrl) {
54
- // Extract the authorization code
55
- const authCode = extractAuthCode(navState.url);
56
- if (authCode) {
57
- onSuccess(authCode);
53
+
54
+ // Close the OAuth window after a small delay to ensure redirect is processed
55
+ setTimeout(() => {
58
56
  if (onComplete) {
57
+ console.log('Closing YouTube OAuth window after callback completion');
59
58
  onComplete();
60
59
  }
61
- }
62
- return;
60
+ }, 500);
63
61
  }
64
- },
65
- [platform, onComplete, onSuccess]
66
- );
67
-
68
- const handleLoadEnd = useCallback(() => {
69
- setLoading(false);
70
- }, []);
71
-
72
- // Extract auth code from redirect URL
73
- const extractAuthCode = (redirectUrl: string): string => {
74
- try {
75
- // First try to extract code from URL parameters
76
- const codeMatch = redirectUrl.match(/code=([^&]+)/);
62
+ return; // Exit early for YouTube to avoid other triggers
63
+ }
64
+
65
+ // Platform-specific success patterns (for non-YouTube platforms)
66
+ const platformSuccessPatterns: Record<string, RegExp[]> = {
67
+ reddit: [
68
+ /reddit\.com\/api\/v1\/authorize\?done=true/,
69
+ /reddit\.com\/api\/v1\/authorize\/success/
70
+ ],
71
+ pinterest: [
72
+ /pinterest\.com\/oauth\/success/,
73
+ /pinterest\.com\/oauth\/complete/
74
+ ],
75
+ linkedin: [
76
+ /linkedin\.com\/oauth\/success/,
77
+ /linkedin\.com\/oauth\/complete/,
78
+ /linkedin\.com\/uas\/oauth2\/authorization\/success/
79
+ ],
80
+ email: [/success/], // Generic success pattern for email
81
+ instagram: [
82
+ /instagram\.com\/oauth\/authorize\?done=true/,
83
+ /instagram\.com\/oauth\/success/
84
+ ]
85
+ };
86
+
87
+ // Check for platform-specific success patterns
88
+ const isPlatformSuccess = platform && platformSuccessPatterns[platform] ?
89
+ platformSuccessPatterns[platform].some(pattern => pattern.test(navState.url)) :
90
+ false;
91
+
92
+ // Check for callback URLs that might contain the authorization code
93
+ const isCallbackUrl = (
94
+ navState.url.includes('/callback') ||
95
+ navState.url.includes('code=') ||
96
+ navState.url.includes('token=') ||
97
+ navState.url.includes('access_token=')
98
+ );
99
+
100
+ // Extract authorization code or token if present
101
+ let authCode = null;
102
+ if (isCallbackUrl) {
103
+ console.log('Detected callback URL with possible code/token');
104
+
105
+ // Try to extract code or token using different patterns
106
+ const codeMatch = navState.url.match(/code=([^&]+)/);
107
+ const tokenMatch = navState.url.match(/(?:token|access_token)=([^&]+)/);
108
+
77
109
  if (codeMatch && codeMatch[1]) {
78
- return codeMatch[1];
110
+ authCode = codeMatch[1];
111
+ console.log('OAuth code extracted:', authCode);
112
+ } else if (tokenMatch && tokenMatch[1]) {
113
+ authCode = tokenMatch[1];
114
+ console.log('OAuth token extracted:', authCode);
79
115
  }
80
116
 
81
- // If that fails, try parsing as URL
82
- const url = new URL(redirectUrl);
83
- return url.searchParams.get('code') || '';
84
- } catch (error) {
85
- console.error('Error extracting auth code:', error);
86
- return '';
117
+ // Call onSuccess with the extracted code/token
118
+ if (authCode) {
119
+ onSuccess(authCode);
120
+ }
121
+ }
122
+
123
+ // If we see the final redirect or platform-specific success, close the OAuth window
124
+ if (isFinalRedirect || isPlatformSuccess) {
125
+ console.log(`Detected success for ${platform}`);
126
+
127
+ // If we haven't already extracted a code/token, consider this a generic success
128
+ if (!authCode) {
129
+ onSuccess('success');
130
+ }
131
+
132
+ // Close the OAuth window
133
+ if (onComplete) {
134
+ console.log('Calling onComplete to close OAuth window');
135
+ onComplete();
136
+ }
137
+ }
138
+ };
139
+
140
+ const handleLoadEnd = () => {
141
+ setIsLoading(false);
142
+ };
143
+
144
+ /**
145
+ * Get platform-specific icon
146
+ */
147
+ const getPlatformIcon = (platform: string): string => {
148
+ switch (platform) {
149
+ case 'instagram':
150
+ return 'photo-camera';
151
+ case 'youtube':
152
+ return 'smart-display';
153
+ case 'pinterest':
154
+ return 'push-pin';
155
+ case 'reddit':
156
+ return 'forum';
157
+ case 'email':
158
+ return 'email';
159
+ default:
160
+ return 'link';
161
+ }
162
+ };
163
+
164
+ /**
165
+ * Get platform-specific color
166
+ */
167
+ const getPlatformColor = (platform: string): string => {
168
+ switch (platform) {
169
+ case 'instagram':
170
+ return '#E1306C';
171
+ case 'youtube':
172
+ return '#FF0000';
173
+ case 'pinterest':
174
+ return '#E60023';
175
+ case 'reddit':
176
+ return '#FF4500';
177
+ case 'email':
178
+ return '#4285F4';
179
+ default:
180
+ return COLORS.primary;
87
181
  }
88
182
  };
89
183
 
@@ -95,10 +189,11 @@ export const OAuthWebView: React.FC<OAuthWebViewProps> = ({
95
189
  </TouchableOpacity>
96
190
  <View style={styles.titleContainer}>
97
191
  <Icon
98
- name={getPlatformIcon(platform || 'default')}
192
+ name={getPlatformIcon(platform)}
99
193
  size={20}
100
- color={getPlatformColor(platform || 'default')}
194
+ color={getPlatformColor(platform)}
101
195
  />
196
+ <Text style={styles.titleText}>{platform.charAt(0).toUpperCase() + platform.slice(1)} OAuth</Text>
102
197
  </View>
103
198
  </View>
104
199
 
@@ -106,65 +201,24 @@ export const OAuthWebView: React.FC<OAuthWebViewProps> = ({
106
201
  source={{ uri: url }}
107
202
  onNavigationStateChange={handleNavigationStateChange}
108
203
  onLoadEnd={handleLoadEnd}
109
- startInLoadingState={true}
110
204
  style={styles.webView}
111
205
  javaScriptEnabled={true}
112
206
  domStorageEnabled={true}
113
207
  sharedCookiesEnabled={true}
114
208
  thirdPartyCookiesEnabled={true}
115
- allowsInlineMediaPlayback={true}
116
- mediaPlaybackRequiresUserAction={false}
117
209
  userAgent="Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1"
118
- mixedContentMode="compatibility"
119
- allowsFullscreenVideo={true}
120
- allowsProtectedMedia={true}
121
210
  />
122
211
 
123
- {loading && (
212
+ {isLoading && (
124
213
  <View style={styles.loadingContainer}>
125
214
  <ActivityIndicator size="large" color={COLORS.primary} />
215
+ <Text style={styles.loadingText}>Loading {platform}...</Text>
126
216
  </View>
127
217
  )}
128
218
  </SafeAreaView>
129
219
  );
130
220
  };
131
221
 
132
- /**
133
- * Get platform-specific icon
134
- */
135
- const getPlatformIcon = (platform: string): string => {
136
- switch (platform) {
137
- case 'instagram':
138
- return 'photo-camera';
139
- case 'youtube':
140
- return 'smart-display';
141
- case 'pinterest':
142
- return 'push-pin';
143
- case 'reddit':
144
- return 'forum';
145
- default:
146
- return 'link';
147
- }
148
- };
149
-
150
- /**
151
- * Get platform-specific color
152
- */
153
- const getPlatformColor = (platform: string): string => {
154
- switch (platform) {
155
- case 'instagram':
156
- return '#E1306C';
157
- case 'youtube':
158
- return '#FF0000';
159
- case 'pinterest':
160
- return '#E60023';
161
- case 'reddit':
162
- return '#FF4500';
163
- default:
164
- return COLORS.primary;
165
- }
166
- };
167
-
168
222
  const styles = StyleSheet.create({
169
223
  container: {
170
224
  flex: 1,
@@ -181,7 +235,15 @@ const styles = StyleSheet.create({
181
235
  },
182
236
  titleContainer: {
183
237
  flex: 1,
238
+ flexDirection: 'row',
184
239
  alignItems: 'center',
240
+ justifyContent: 'center',
241
+ },
242
+ titleText: {
243
+ marginLeft: 8,
244
+ fontSize: 16,
245
+ fontWeight: '500',
246
+ color: '#000',
185
247
  },
186
248
  closeButton: {
187
249
  padding: 8,
@@ -198,4 +260,9 @@ const styles = StyleSheet.create({
198
260
  alignItems: 'center',
199
261
  justifyContent: 'center',
200
262
  },
263
+ loadingText: {
264
+ marginTop: 10,
265
+ fontSize: 16,
266
+ color: '#666',
267
+ },
201
268
  });